@next-open-ai/openclawx 0.8.17 → 0.8.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +24 -8
  2. package/apps/desktop/renderer/dist/assets/index-B0_RWD2F.css +10 -0
  3. package/apps/desktop/renderer/dist/assets/index-B8jRTtME.js +89 -0
  4. package/apps/desktop/renderer/dist/index.html +2 -2
  5. package/dist/core/agent/agent-manager.d.ts +10 -4
  6. package/dist/core/agent/agent-manager.js +49 -22
  7. package/dist/core/agent/proxy/adapters/coze-adapter.js +7 -0
  8. package/dist/core/agent/proxy/adapters/local-adapter.js +4 -11
  9. package/dist/core/agent/proxy/adapters/openclawx-adapter.js +7 -0
  10. package/dist/core/agent/proxy/adapters/opencode-adapter.d.ts +11 -0
  11. package/dist/core/agent/proxy/adapters/opencode-adapter.js +716 -0
  12. package/dist/core/agent/proxy/adapters/opencode-free-models.d.ts +20 -0
  13. package/dist/core/agent/proxy/adapters/opencode-free-models.js +14 -0
  14. package/dist/core/agent/proxy/adapters/opencode-local-runner.d.ts +5 -0
  15. package/dist/core/agent/proxy/adapters/opencode-local-runner.js +86 -0
  16. package/dist/core/agent/proxy/index.js +3 -1
  17. package/dist/core/agent/proxy/run-for-channel.js +1 -1
  18. package/dist/core/agent/proxy/types.d.ts +2 -0
  19. package/dist/core/agent/run.js +1 -1
  20. package/dist/core/config/desktop-config.d.ts +71 -3
  21. package/dist/core/config/desktop-config.js +222 -24
  22. package/dist/core/memory/compaction-extension.d.ts +4 -3
  23. package/dist/core/memory/compaction-extension.js +6 -14
  24. package/dist/core/memory/embedding-types.d.ts +10 -0
  25. package/dist/core/memory/embedding-types.js +5 -0
  26. package/dist/core/memory/embedding.d.ts +2 -1
  27. package/dist/core/memory/embedding.js +38 -6
  28. package/dist/core/memory/index.js +3 -0
  29. package/dist/core/memory/local-embedding-llama.d.ts +13 -0
  30. package/dist/core/memory/local-embedding-llama.js +76 -0
  31. package/dist/core/memory/local-embedding.d.ts +10 -0
  32. package/dist/core/memory/local-embedding.js +29 -0
  33. package/dist/core/memory/persist-compaction-on-close.d.ts +14 -0
  34. package/dist/core/memory/persist-compaction-on-close.js +32 -0
  35. package/dist/core/tools/bookmark-tool.d.ts +4 -0
  36. package/dist/core/tools/bookmark-tool.js +59 -3
  37. package/dist/core/tools/index.d.ts +2 -1
  38. package/dist/core/tools/index.js +2 -1
  39. package/dist/core/tools/memory-recall-tool.d.ts +6 -0
  40. package/dist/core/tools/memory-recall-tool.js +77 -0
  41. package/dist/gateway/channel/adapters/wechat.d.ts +24 -0
  42. package/dist/gateway/channel/adapters/wechat.js +205 -0
  43. package/dist/gateway/methods/agent-cancel.d.ts +3 -1
  44. package/dist/gateway/methods/agent-cancel.js +13 -2
  45. package/dist/gateway/methods/agent-chat.js +112 -23
  46. package/dist/gateway/methods/run-scheduled-task.js +3 -7
  47. package/dist/gateway/proxy-run-abort.d.ts +6 -0
  48. package/dist/gateway/proxy-run-abort.js +39 -0
  49. package/dist/gateway/server.js +62 -7
  50. package/dist/server/agent-config/agent-config.controller.d.ts +2 -2
  51. package/dist/server/agent-config/agent-config.controller.js +8 -4
  52. package/dist/server/agent-config/agent-config.module.js +3 -1
  53. package/dist/server/agent-config/agent-config.service.d.ts +41 -6
  54. package/dist/server/agent-config/agent-config.service.js +30 -3
  55. package/dist/server/agents/agents.service.js +1 -1
  56. package/dist/server/bootstrap.js +9 -2
  57. package/dist/server/config/config.controller.d.ts +31 -2
  58. package/dist/server/config/config.controller.js +14 -0
  59. package/dist/server/config/config.module.js +2 -2
  60. package/dist/server/config/config.service.d.ts +14 -1
  61. package/dist/server/config/config.service.js +1 -0
  62. package/dist/server/workspace/workspace.service.d.ts +7 -0
  63. package/dist/server/workspace/workspace.service.js +16 -0
  64. package/package.json +6 -1
  65. package/skills/url-bookmark/SKILL.md +12 -12
  66. package/apps/desktop/renderer/dist/assets/index-DmIfN-Vc.js +0 -89
  67. package/apps/desktop/renderer/dist/assets/index-DvB8yW8I.css +0 -10
@@ -11,8 +11,8 @@
11
11
  <link
12
12
  href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Roboto+Mono:wght@400;500&display=swap"
13
13
  rel="stylesheet">
14
- <script type="module" crossorigin src="/assets/index-DmIfN-Vc.js"></script>
15
- <link rel="stylesheet" crossorigin href="/assets/index-DvB8yW8I.css">
14
+ <script type="module" crossorigin src="/assets/index-B8jRTtME.js"></script>
15
+ <link rel="stylesheet" crossorigin href="/assets/index-B0_RWD2F.css">
16
16
  </head>
17
17
 
18
18
  <body>
@@ -14,6 +14,8 @@ export declare class AgentManager {
14
14
  private sessions;
15
15
  /** 每个 session 最后被使用的时间戳,用于 LRU 淘汰 */
16
16
  private sessionLastActiveAt;
17
+ /** 每个 SessionAgent 当前最新的 compaction summary,关闭会话时写入向量库(infotype: compaction) */
18
+ private sessionLatestCompactionSummary;
17
19
  private agentDir;
18
20
  private workspaceDir;
19
21
  private skillPaths;
@@ -60,13 +62,17 @@ export declare class AgentManager {
60
62
  mcpServers?: McpServerConfig[];
61
63
  /** 自定义系统提示词(来自 agent 配置),会与技能等一起组成最终 systemPrompt */
62
64
  systemPrompt?: string;
65
+ /** 是否使用长记忆(memory_recall/save_experience);默认 true */
66
+ useLongMemory?: boolean;
63
67
  }): Promise<AgentSession>;
64
68
  /** 按复合 key 获取(key = sessionId + "::" + agentId) */
65
69
  getSession(compositeKey: string): AgentSession | undefined;
66
- /** 删除一个 Agent Session(传入复合 key) */
67
- deleteSession(compositeKey: string): boolean;
68
- /** 按业务 sessionId 删除该会话下所有 agent Core Session(如删除会话时) */
69
- deleteSessionsByBusinessId(sessionId: string): void;
70
+ /** 按业务 sessionId 查找一个 Session(取最近活跃的),用于 agent.cancel */
71
+ getSessionBySessionId(sessionId: string): AgentSession | undefined;
72
+ /** 删除一个 Agent Session(传入复合 key);关闭前将本 session 最新 compaction summary 写入向量库 */
73
+ deleteSession(compositeKey: string): Promise<boolean>;
74
+ /** 按业务 sessionId 删除该会话下所有 agent 的 Core Session(如删除会话时);关闭前将各 session 最新 compaction 写入向量库 */
75
+ deleteSessionsByBusinessId(sessionId: string): Promise<void>;
70
76
  clearAll(): void;
71
77
  }
72
78
  export declare const agentManager: AgentManager;
@@ -2,8 +2,9 @@ import { createAgentSession, AuthStorage, DefaultResourceLoader, ModelRegistry,
2
2
  import { join } from "node:path";
3
3
  import { existsSync, mkdirSync } from "node:fs";
4
4
  import { createCompactionMemoryExtensionFactory } from "../memory/compaction-extension.js";
5
- import { getCompactionContextForSystemPrompt } from "../memory/index.js";
6
- import { createBrowserTool, createSaveExperienceTool, createInstallSkillTool, createSwitchAgentTool, createListAgentsTool, createCreateAgentTool, createGetBookmarkTagsTool, createSaveBookmarkTool } from "../tools/index.js";
5
+ import { addMemory } from "../memory/index.js";
6
+ import { persistStoredCompactionForSession, persistStoredCompactionForBusinessSession, } from "../memory/persist-compaction-on-close.js";
7
+ import { createBrowserTool, createSaveExperienceTool, createMemoryRecallTool, createInstallSkillTool, createSwitchAgentTool, createListAgentsTool, createCreateAgentTool, createGetBookmarkTagsTool, createSaveBookmarkTool, createAddBookmarkTagTool } from "../tools/index.js";
7
8
  /** Agent Session 缓存 key:sessionId + "::" + agentId,同一业务 session 下不同 agent 各自一个 Core Session */
8
9
  const COMPOSITE_KEY_SEP = "::";
9
10
  function toCompositeKey(sessionId, agentId) {
@@ -24,6 +25,8 @@ export class AgentManager {
24
25
  sessions = new Map();
25
26
  /** 每个 session 最后被使用的时间戳,用于 LRU 淘汰 */
26
27
  sessionLastActiveAt = new Map();
28
+ /** 每个 SessionAgent 当前最新的 compaction summary,关闭会话时写入向量库(infotype: compaction) */
29
+ sessionLatestCompactionSummary = new Map();
27
30
  agentDir;
28
31
  workspaceDir;
29
32
  skillPaths = [];
@@ -89,10 +92,16 @@ You have access to a \`browser\` tool for web automation:
89
92
 
90
93
  Use refs from snapshots (e.g., @e1) for reliable element selection.
91
94
  For downloads, provide either a direct URL or a selector to click.`;
95
+ const experienceMemoryDesc = `
96
+ ## Long-term memory
97
+
98
+ - **save_experience**: Store summaries in long-term memory. **At the end of each round of conversation** (after you have finished replying to the user), briefly summarize the main outcomes, conclusions, or reusable points and call \`save_experience\` with that summary.
99
+ - **memory_recall**: Retrieve relevant memories by semantic search. **When the user asks about past work, decisions, dates, people, preferences, todos, complex tasks, scheduled tasks, or anything that may need past experience**, call \`memory_recall\` first with a suitable query, then answer using the recalled content. Do not inject any history or memory into your replies unless you have just retrieved it via \`memory_recall\` for that question.`;
92
100
  const parts = [
93
101
  "You are a helpful assistant. When users ask about skills, explain what skills are available.",
94
102
  browserToolDesc,
95
103
  skillsBlock,
104
+ experienceMemoryDesc,
96
105
  ].filter(Boolean);
97
106
  return parts.join("\n\n");
98
107
  }
@@ -106,27 +115,25 @@ For downloads, provide either a direct URL or a selector to click.`;
106
115
  const systemPrompt = this.buildSystemPrompt(loadedSkills);
107
116
  return { systemPrompt, skills: loadedSkills };
108
117
  }
109
- createResourceLoader(workspaceDir, sessionId, compactionBlock, customAgentPrompt, identity) {
118
+ createResourceLoader(workspaceDir, sessionId, customAgentPrompt, identity, onUpdateLatestCompaction) {
110
119
  const loader = new DefaultResourceLoader({
111
120
  cwd: workspaceDir,
112
121
  agentDir: this.agentDir,
113
122
  noSkills: true, // Disable SDK's built-in skills logic to take full control
114
123
  additionalSkillPaths: this.resolveSkillPaths(workspaceDir),
115
- extensionFactories: sessionId ? [createCompactionMemoryExtensionFactory(sessionId)] : [],
124
+ extensionFactories: sessionId && onUpdateLatestCompaction
125
+ ? [createCompactionMemoryExtensionFactory(sessionId, onUpdateLatestCompaction)]
126
+ : [],
116
127
  systemPromptOverride: (base) => {
117
128
  const loadedSkills = loader.getSkills().skills;
118
- let basePrompt = this.buildSystemPrompt(loadedSkills);
129
+ const basePrompt = this.buildSystemPrompt(loadedSkills);
119
130
  const withCustom = customAgentPrompt && customAgentPrompt.trim()
120
131
  ? customAgentPrompt.trim() + "\n\n" + basePrompt
121
132
  : basePrompt;
122
- const withIdentity = identity && identity.agentId
133
+ return identity && identity.agentId
123
134
  ? `[Session identity] You are the agent with ID: ${identity.agentId}, workspace: ${identity.workspace || identity.agentId}. When asked which agent you are, answer according to this identity.\n\n` +
124
135
  withCustom
125
136
  : withCustom;
126
- if (compactionBlock?.trim()) {
127
- return withIdentity + "\n\n" + compactionBlock.trim();
128
- }
129
- return withIdentity;
130
137
  },
131
138
  });
132
139
  return loader;
@@ -182,7 +189,7 @@ For downloads, provide either a direct URL or a selector to click.`;
182
189
  }
183
190
  }
184
191
  if (oldestId != null) {
185
- this.deleteSession(oldestId);
192
+ await this.deleteSession(oldestId);
186
193
  }
187
194
  }
188
195
  const workspaceRoot = getOpenbotWorkspaceDir();
@@ -238,8 +245,7 @@ For downloads, provide either a direct URL or a selector to click.`;
238
245
  return process.env.OPENAI_API_KEY;
239
246
  return process.env.OPENAI_API_KEY;
240
247
  });
241
- const compactionBlock = await getCompactionContextForSystemPrompt(sessionId);
242
- const loader = this.createResourceLoader(sessionWorkspaceDir, sessionId, compactionBlock, options.systemPrompt, { agentId, workspace: workspaceName });
248
+ const loader = this.createResourceLoader(sessionWorkspaceDir, sessionId, options.systemPrompt, { agentId, workspace: workspaceName }, (summary) => this.sessionLatestCompactionSummary.set(compositeKey, summary));
243
249
  await loader.reload();
244
250
  const coreTools = {
245
251
  read: createReadTool(sessionWorkspaceDir),
@@ -250,16 +256,19 @@ For downloads, provide either a direct URL or a selector to click.`;
250
256
  grep: createGrepTool(sessionWorkspaceDir),
251
257
  ls: createLsTool(sessionWorkspaceDir),
252
258
  };
259
+ const useLongMemory = options.useLongMemory !== false;
253
260
  const mcpTools = await createMcpToolsForSession({ mcpServers: options.mcpServers });
254
261
  const customTools = [
255
262
  createBrowserTool(sessionWorkspaceDir),
256
263
  createSaveExperienceTool(sessionId),
264
+ createMemoryRecallTool(useLongMemory),
257
265
  createInstallSkillTool(options.targetAgentId ?? agentId),
258
266
  createSwitchAgentTool(sessionId),
259
267
  createListAgentsTool(),
260
268
  createCreateAgentTool(),
261
269
  createGetBookmarkTagsTool(),
262
270
  createSaveBookmarkTool(),
271
+ createAddBookmarkTagTool(),
263
272
  ...mcpTools,
264
273
  ];
265
274
  const { session } = await createAgentSession({
@@ -285,24 +294,42 @@ For downloads, provide either a direct URL or a selector to click.`;
285
294
  getSession(compositeKey) {
286
295
  return this.sessions.get(compositeKey);
287
296
  }
288
- /** 删除一个 Agent Session(传入复合 key) */
289
- deleteSession(compositeKey) {
297
+ /** 按业务 sessionId 查找一个 Session(取最近活跃的),用于 agent.cancel */
298
+ getSessionBySessionId(sessionId) {
299
+ const prefix = sessionId + COMPOSITE_KEY_SEP;
300
+ let bestKey;
301
+ let bestAt = 0;
302
+ for (const key of this.sessions.keys()) {
303
+ if (!key.startsWith(prefix))
304
+ continue;
305
+ const at = this.sessionLastActiveAt.get(key) ?? 0;
306
+ if (at >= bestAt) {
307
+ bestAt = at;
308
+ bestKey = key;
309
+ }
310
+ }
311
+ return bestKey != null ? this.sessions.get(bestKey) : undefined;
312
+ }
313
+ /** 删除一个 Agent Session(传入复合 key);关闭前将本 session 最新 compaction summary 写入向量库 */
314
+ async deleteSession(compositeKey) {
315
+ await persistStoredCompactionForSession(this.sessionLatestCompactionSummary, compositeKey, addMemory);
290
316
  this.sessionLastActiveAt.delete(compositeKey);
291
317
  return this.sessions.delete(compositeKey);
292
318
  }
293
- /** 按业务 sessionId 删除该会话下所有 agent 的 Core Session(如删除会话时) */
294
- deleteSessionsByBusinessId(sessionId) {
319
+ /** 按业务 sessionId 删除该会话下所有 agent 的 Core Session(如删除会话时);关闭前将各 session 最新 compaction 写入向量库 */
320
+ async deleteSessionsByBusinessId(sessionId) {
295
321
  const prefix = sessionId + COMPOSITE_KEY_SEP;
296
- for (const key of Array.from(this.sessions.keys())) {
297
- if (key.startsWith(prefix)) {
298
- this.sessionLastActiveAt.delete(key);
299
- this.sessions.delete(key);
300
- }
322
+ const keysToProcess = Array.from(this.sessions.keys()).filter((k) => k.startsWith(prefix));
323
+ await persistStoredCompactionForBusinessSession(this.sessionLatestCompactionSummary, keysToProcess, sessionId, addMemory);
324
+ for (const key of keysToProcess) {
325
+ this.sessionLastActiveAt.delete(key);
326
+ this.sessions.delete(key);
301
327
  }
302
328
  }
303
329
  clearAll() {
304
330
  this.sessions.clear();
305
331
  this.sessionLastActiveAt.clear();
332
+ this.sessionLatestCompactionSummary.clear();
306
333
  }
307
334
  }
308
335
  // Singleton for easy access (e.g., from Gateway)
@@ -176,6 +176,13 @@ export const cozeAdapter = {
176
176
  };
177
177
  const controller = new AbortController();
178
178
  const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
179
+ const userSignal = options.signal;
180
+ if (userSignal) {
181
+ if (userSignal.aborted)
182
+ controller.abort();
183
+ else
184
+ userSignal.addEventListener("abort", () => controller.abort(), { once: true });
185
+ }
179
186
  try {
180
187
  console.log(`[Coze] POST ${url} (stream=true)`);
181
188
  const res = await fetch(url, {
@@ -3,7 +3,6 @@
3
3
  */
4
4
  import { agentManager } from "../../agent-manager.js";
5
5
  import { getDesktopConfig } from "../../../config/desktop-config.js";
6
- import { getExperienceContextForUserMessage } from "../../../memory/index.js";
7
6
  const CHANNEL_AGENT_TIMEOUT_MS = 120_000;
8
7
  export const localAdapter = {
9
8
  type: "local",
@@ -21,6 +20,7 @@ export const localAdapter = {
21
20
  targetAgentId: agentId,
22
21
  mcpServers: config.mcpServers,
23
22
  systemPrompt: config.systemPrompt,
23
+ useLongMemory: config.useLongMemory,
24
24
  });
25
25
  let resolveDone;
26
26
  const donePromise = new Promise((r) => {
@@ -39,11 +39,7 @@ export const localAdapter = {
39
39
  }
40
40
  });
41
41
  try {
42
- const experienceBlock = await getExperienceContextForUserMessage();
43
- const userMessageToSend = experienceBlock.trim().length > 0
44
- ? `${experienceBlock}\n\n用户问题:\n${message}`
45
- : message;
46
- await session.sendUserMessage(userMessageToSend, { deliverAs: "followUp" });
42
+ await session.sendUserMessage(message, { deliverAs: "followUp" });
47
43
  await Promise.race([
48
44
  donePromise,
49
45
  new Promise((_, rej) => setTimeout(() => rej(new Error("Channel agent reply timeout")), CHANNEL_AGENT_TIMEOUT_MS)),
@@ -67,6 +63,7 @@ export const localAdapter = {
67
63
  targetAgentId: agentId,
68
64
  mcpServers: config.mcpServers,
69
65
  systemPrompt: config.systemPrompt,
66
+ useLongMemory: config.useLongMemory,
70
67
  });
71
68
  const chunks = [];
72
69
  let resolveDone;
@@ -82,11 +79,7 @@ export const localAdapter = {
82
79
  }
83
80
  });
84
81
  try {
85
- const experienceBlock = await getExperienceContextForUserMessage();
86
- const userMessageToSend = experienceBlock.trim().length > 0
87
- ? `${experienceBlock}\n\n用户问题:\n${message}`
88
- : message;
89
- await session.sendUserMessage(userMessageToSend, { deliverAs: "followUp" });
82
+ await session.sendUserMessage(message, { deliverAs: "followUp" });
90
83
  await Promise.race([
91
84
  donePromise,
92
85
  new Promise((_, rej) => setTimeout(() => rej(new Error("Channel agent reply timeout")), CHANNEL_AGENT_TIMEOUT_MS)),
@@ -25,6 +25,13 @@ export const openclawxAdapter = {
25
25
  const body = { sessionId: options.sessionId, message: options.message, agentId: options.agentId };
26
26
  const controller = new AbortController();
27
27
  const timeoutId = setTimeout(() => controller.abort(), REQUEST_TIMEOUT_MS);
28
+ const userSignal = options.signal;
29
+ if (userSignal) {
30
+ if (userSignal.aborted)
31
+ controller.abort();
32
+ else
33
+ userSignal.addEventListener("abort", () => controller.abort(), { once: true });
34
+ }
28
35
  try {
29
36
  const res = await fetch(url, {
30
37
  method: "POST",
@@ -0,0 +1,11 @@
1
+ import type { IAgentProxyAdapter } from "../types.js";
2
+ export interface ResolvedOpenCodeConfig {
3
+ baseUrl: string;
4
+ username: string;
5
+ password?: string;
6
+ model: {
7
+ providerID: string;
8
+ modelID: string;
9
+ };
10
+ }
11
+ export declare const opencodeAdapter: IAgentProxyAdapter;