@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
@@ -7,17 +7,26 @@
7
7
  * - /channel → 通道模块(占位)
8
8
  * - 其余 → 静态资源
9
9
  */
10
- /* Avoid MaxListenersExceededWarning */
11
- const Et = globalThis.EventTarget;
12
- if (Et?.prototype?.addEventListener && Et.prototype.setMaxListeners) {
13
- const add = Et.prototype.addEventListener;
14
- Et.prototype.addEventListener = function (type, listener, options) {
15
- if (type === "abort" && typeof this.setMaxListeners === "function") {
16
- this.setMaxListeners(32);
10
+ /* Avoid MaxListenersExceededWarning for AbortSignal (e.g. agent 多轮 tool 调用,Electron 下需尽早 patch) */
11
+ const g = globalThis;
12
+ const limit = 128;
13
+ function patchAddEventListener(proto) {
14
+ if (!proto?.addEventListener)
15
+ return;
16
+ const add = proto.addEventListener;
17
+ proto.addEventListener = function (type, listener, options) {
18
+ if (type === "abort") {
19
+ try {
20
+ if (typeof this.setMaxListeners === "function")
21
+ this.setMaxListeners(limit);
22
+ }
23
+ catch (_) { }
17
24
  }
18
25
  return add.call(this, type, listener, options);
19
26
  };
20
27
  }
28
+ patchAddEventListener(g.EventTarget?.prototype);
29
+ patchAddEventListener(g.AbortSignal?.prototype);
21
30
  import express from "express";
22
31
  import { createServer } from "http";
23
32
  import { WebSocketServer } from "ws";
@@ -41,6 +50,7 @@ import { registerChannel, startAllChannels, stopAllChannels } from "./channel/re
41
50
  import { createFeishuChannel } from "./channel/adapters/feishu.js";
42
51
  import { createDingTalkChannel } from "./channel/adapters/dingtalk.js";
43
52
  import { createTelegramChannel } from "./channel/adapters/telegram.js";
53
+ import { createWechatChannel, getWechatQrCode, getWechatStatus, refreshWechatQrCode } from "./channel/adapters/wechat.js";
44
54
  import { setChannelSessionPersistence } from "./channel/session-persistence.js";
45
55
  import { setSessionCurrentAgentResolver, setSessionCurrentAgentUpdater, setAgentListProvider, setCreateAgentProvider, } from "../core/session-current-agent.js";
46
56
  import { AgentsService } from "../server/agents/agents.service.js";
@@ -65,6 +75,7 @@ const MIME_TYPES = {
65
75
  ".eot": "application/vnd.ms-fontobject",
66
76
  };
67
77
  export async function startGatewayServer(port = 38080) {
78
+ process.env.PORT = String(port);
68
79
  await ensureDesktopConfigInitialized();
69
80
  console.log(`Starting gateway server on port ${port}...`);
70
81
  setBackendBaseUrl(`http://localhost:${port}`);
@@ -141,6 +152,36 @@ export async function startGatewayServer(port = 38080) {
141
152
  res.status(code).json({ success: false, message });
142
153
  }
143
154
  });
155
+ // WeChat QR code & status API (must be before NestJS catch-all)
156
+ gatewayExpress.get(`${PATHS.SERVER_API}/wechat/qrcode`, (_req, res) => {
157
+ res.setHeader("Access-Control-Allow-Origin", "*");
158
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
159
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type");
160
+ res.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
161
+ const qrcode = getWechatQrCode();
162
+ const { status, userName } = getWechatStatus();
163
+ res.status(200).json({ qrcode, status, userName });
164
+ });
165
+ // Refresh: restart Wechaty bot to get a fresh QR code
166
+ gatewayExpress.post(`${PATHS.SERVER_API}/wechat/qrcode/refresh`, async (_req, res) => {
167
+ res.setHeader("Access-Control-Allow-Origin", "*");
168
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
169
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type");
170
+ res.setHeader("Cache-Control", "no-store");
171
+ try {
172
+ await refreshWechatQrCode();
173
+ // Wait a bit for scan event to fire
174
+ await new Promise(r => setTimeout(r, 3000));
175
+ const qrcode = getWechatQrCode();
176
+ const { status, userName } = getWechatStatus();
177
+ console.log(`[WeChat API refresh] qrcode=${qrcode ? 'has_data' : 'null'}, status=${status}`);
178
+ res.status(200).json({ qrcode, status, userName });
179
+ }
180
+ catch (e) {
181
+ console.error("[WeChat API refresh] error:", e);
182
+ res.status(500).json({ error: e?.message || String(e) });
183
+ }
184
+ });
144
185
  gatewayExpress.use(PATHS.SERVER_API, authHookServerApi, nestExpress);
145
186
  gatewayExpress.use(PATHS.CHANNEL, authHookChannel, (req, res) => handleChannel(req, res));
146
187
  gatewayExpress.use(PATHS.SSE, authHookSse, (req, res) => handleSse(req, res));
@@ -259,6 +300,20 @@ export async function startGatewayServer(port = 38080) {
259
300
  else if (telegramCfg?.enabled) {
260
301
  console.warn("[Channel] Telegram is enabled but botToken is missing; skip. Check Settings → Channels.");
261
302
  }
303
+ const wechatCfg = channelsConfig.wechat;
304
+ if (wechatCfg?.enabled) {
305
+ try {
306
+ const wechatChannel = createWechatChannel({
307
+ puppet: wechatCfg.puppet?.trim() || undefined,
308
+ defaultAgentId: wechatCfg.defaultAgentId?.trim() || "default",
309
+ });
310
+ registerChannel(wechatChannel);
311
+ console.log("[Channel] WeChat channel registered");
312
+ }
313
+ catch (e) {
314
+ console.warn("WeChat channel register failed:", e);
315
+ }
316
+ }
262
317
  await startAllChannels();
263
318
  const close = async () => {
264
319
  console.log("Closing gateway server...");
@@ -25,11 +25,11 @@ export declare class AgentConfigController {
25
25
  success: boolean;
26
26
  data: AgentConfigItem;
27
27
  }>;
28
- updateAgent(id: string, body: Partial<Pick<AgentConfigItem, 'name' | 'provider' | 'model' | 'modelItemCode' | 'mcpServers' | 'systemPrompt' | 'icon' | 'runnerType' | 'coze' | 'openclawx'>>): Promise<{
28
+ updateAgent(id: string, body: Partial<Pick<AgentConfigItem, 'name' | 'provider' | 'model' | 'modelItemCode' | 'mcpServers' | 'systemPrompt' | 'icon' | 'runnerType' | 'coze' | 'openclawx' | 'opencode'>>): Promise<{
29
29
  success: boolean;
30
30
  data: AgentConfigItem;
31
31
  }>;
32
- deleteAgent(id: string): Promise<{
32
+ deleteAgent(id: string, deleteWorkspaceDir?: string): Promise<{
33
33
  success: boolean;
34
34
  }>;
35
35
  }
@@ -10,7 +10,7 @@ var __metadata = (this && this.__metadata) || function (k, v) {
10
10
  var __param = (this && this.__param) || function (paramIndex, decorator) {
11
11
  return function (target, key) { decorator(target, key, paramIndex); }
12
12
  };
13
- import { Controller, Get, Post, Put, Delete, Body, Param } from '@nestjs/common';
13
+ import { Controller, Get, Post, Put, Delete, Body, Param, Query } from '@nestjs/common';
14
14
  import { AgentConfigService } from './agent-config.service.js';
15
15
  let AgentConfigController = class AgentConfigController {
16
16
  agentConfigService;
@@ -36,8 +36,11 @@ let AgentConfigController = class AgentConfigController {
36
36
  const agent = await this.agentConfigService.updateAgent(id, body);
37
37
  return { success: true, data: agent };
38
38
  }
39
- async deleteAgent(id) {
40
- await this.agentConfigService.deleteAgent(id);
39
+ async deleteAgent(id, deleteWorkspaceDir) {
40
+ const options = deleteWorkspaceDir === 'true' || deleteWorkspaceDir === '1'
41
+ ? { deleteWorkspaceDir: true }
42
+ : undefined;
43
+ await this.agentConfigService.deleteAgent(id, options);
41
44
  return { success: true };
42
45
  }
43
46
  };
@@ -72,8 +75,9 @@ __decorate([
72
75
  __decorate([
73
76
  Delete(':id'),
74
77
  __param(0, Param('id')),
78
+ __param(1, Query('deleteWorkspaceDir')),
75
79
  __metadata("design:type", Function),
76
- __metadata("design:paramtypes", [String]),
80
+ __metadata("design:paramtypes", [String, String]),
77
81
  __metadata("design:returntype", Promise)
78
82
  ], AgentConfigController.prototype, "deleteAgent", null);
79
83
  AgentConfigController = __decorate([
@@ -4,13 +4,15 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { Module } from '@nestjs/common';
7
+ import { Module, forwardRef } from '@nestjs/common';
8
8
  import { AgentConfigService } from './agent-config.service.js';
9
9
  import { AgentConfigController } from './agent-config.controller.js';
10
+ import { WorkspaceModule } from '../workspace/workspace.module.js';
10
11
  let AgentConfigModule = class AgentConfigModule {
11
12
  };
12
13
  AgentConfigModule = __decorate([
13
14
  Module({
15
+ imports: [forwardRef(() => WorkspaceModule)],
14
16
  controllers: [AgentConfigController],
15
17
  providers: [AgentConfigService],
16
18
  exports: [AgentConfigService],
@@ -1,8 +1,10 @@
1
1
  import type { McpServerConfig } from '../../core/mcp/index.js';
2
+ import { DatabaseService } from '../database/database.service.js';
3
+ import { WorkspaceService } from '../workspace/workspace.service.js';
2
4
  /** 缺省智能体 ID / 工作空间名,不可删除;对应目录 ~/.openbot/workspace/default */
3
5
  export declare const DEFAULT_AGENT_ID = "default";
4
- /** 执行器类型:local=本机,coze/openclawx=远程代理 */
5
- export type AgentRunnerType = 'local' | 'coze' | 'openclawx';
6
+ /** 执行器类型:local=本机,coze/openclawx/opencode=远程代理 */
7
+ export type AgentRunnerType = 'local' | 'coze' | 'openclawx' | 'opencode';
6
8
  /** Coze 站点:cn=国内 api.coze.cn,com=国际 api.coze.com,凭证不通用 */
7
9
  export type CozeRegion = 'cn' | 'com';
8
10
  /** 某站点的 Bot 凭证 */
@@ -21,6 +23,27 @@ export interface AgentOpenClawXConfig {
21
23
  baseUrl: string;
22
24
  apiKey?: string;
23
25
  }
26
+ /** OpenCode 启动模式:local=本应用启动本机服务;remote=连接已运行的服务 */
27
+ export type OpenCodeServerMode = "local" | "remote";
28
+ /** OpenCode 代理配置:按官方 Server API 或 OpenAI 兼容端点 */
29
+ export interface AgentOpenCodeConfig {
30
+ /** 启动模式:local=本应用按需启动;remote=连接已有服务 */
31
+ mode?: OpenCodeServerMode;
32
+ /** 地址(仅 remote 必填;local 时由适配器使用 127.0.0.1) */
33
+ address?: string;
34
+ port: number;
35
+ password?: string;
36
+ /** Basic 认证用户名(默认 opencode) */
37
+ username?: string;
38
+ /** @deprecated 仅保留向后兼容,产品仅支持官方 Server API */
39
+ apiStyle?: "server" | "openai";
40
+ path?: string;
41
+ streamPath?: string;
42
+ /** 默认模型(local 时写入启动配置;remote 时作为请求 model) */
43
+ model?: string;
44
+ /** 工作目录(仅 local 模式):启动 opencode serve 时的 cwd,留空则使用进程当前目录 */
45
+ workingDirectory?: string;
46
+ }
24
47
  /**
25
48
  * 智能体列表与配置使用文件存储(~/.openbot/desktop/agents.json),不使用 SQLite。
26
49
  * 会话与消息历史使用 SQLite;Skills、工作空间文档为目录文件管理。
@@ -41,17 +64,27 @@ export interface AgentConfigItem {
41
64
  systemPrompt?: string;
42
65
  /** 智能体图标标识(前端预设图标 id,如 default、star、code 等) */
43
66
  icon?: string;
44
- /** 执行器类型:local=本机,coze/openclawx=远程代理 */
67
+ /** 执行器类型:local=本机,coze/openclawx/opencode=远程代理 */
45
68
  runnerType?: AgentRunnerType;
46
69
  /** Coze 代理配置(runnerType 为 coze 时使用) */
47
70
  coze?: AgentCozeConfig;
48
71
  /** OpenClawX 代理配置(runnerType 为 openclawx 时使用) */
49
72
  openclawx?: AgentOpenClawXConfig;
73
+ /** OpenCode 代理配置(runnerType 为 opencode 时使用) */
74
+ opencode?: AgentOpenCodeConfig;
75
+ /** 是否使用经验(长记忆):memory_recall / save_experience;默认 true */
76
+ useLongMemory?: boolean;
77
+ }
78
+ export interface DeleteAgentOptions {
79
+ /** 是否同时删除该工作区在磁盘上的目录及文件;默认 false(仅删数据库中的工作区相关数据,保留目录) */
80
+ deleteWorkspaceDir?: boolean;
50
81
  }
51
82
  export declare class AgentConfigService {
83
+ private readonly db;
84
+ private readonly workspaceService;
52
85
  private configDir;
53
86
  private agentsPath;
54
- constructor();
87
+ constructor(db: DatabaseService, workspaceService: WorkspaceService);
55
88
  private ensureConfigDir;
56
89
  private readAgentsFile;
57
90
  private writeAgentsFile;
@@ -71,8 +104,10 @@ export declare class AgentConfigService {
71
104
  /** 智能体图标标识 */
72
105
  icon?: string;
73
106
  }): Promise<AgentConfigItem>;
74
- updateAgent(id: string, updates: Partial<Pick<AgentConfigItem, 'name' | 'provider' | 'model' | 'modelItemCode' | 'mcpServers' | 'systemPrompt' | 'icon' | 'runnerType' | 'coze' | 'openclawx'>>): Promise<AgentConfigItem>;
75
- deleteAgent(id: string): Promise<void>;
107
+ updateAgent(id: string, updates: Partial<Pick<AgentConfigItem, 'name' | 'provider' | 'model' | 'modelItemCode' | 'mcpServers' | 'systemPrompt' | 'icon' | 'runnerType' | 'coze' | 'openclawx' | 'opencode' | 'useLongMemory'>>): Promise<AgentConfigItem>;
108
+ deleteAgent(id: string, options?: DeleteAgentOptions): Promise<void>;
109
+ /** 仅删除数据库中与该工作区相关的数据(会话、定时任务、收藏等),不删磁盘目录 */
110
+ private deleteWorkspaceDataFromDb;
76
111
  /**
77
112
  * 根据 config 的 defaultProvider / defaultModel / defaultModelItemCode 及 configuredModels 同步 agents.json 中缺省智能体的 provider、model、modelItemCode。
78
113
  * 在桌面保存配置(如修改默认模型)后调用,保证 agents 与 config 一致。
@@ -12,6 +12,8 @@ import { readFile, writeFile, mkdir } from 'fs/promises';
12
12
  import { join } from 'path';
13
13
  import { existsSync } from 'fs';
14
14
  import { homedir } from 'os';
15
+ import { DatabaseService } from '../database/database.service.js';
16
+ import { WorkspaceService } from '../workspace/workspace.service.js';
15
17
  /** 工作空间名仅允许英文、数字、下划线、连字符 */
16
18
  const WORKSPACE_NAME_REGEX = /^[a-zA-Z0-9_-]+$/;
17
19
  /** 缺省智能体 ID / 工作空间名,不可删除;对应目录 ~/.openbot/workspace/default */
@@ -19,9 +21,13 @@ export const DEFAULT_AGENT_ID = 'default';
19
21
  /** 主智能体(default)的默认展示名 */
20
22
  const DEFAULT_AGENT_NAME = '主智能体';
21
23
  let AgentConfigService = class AgentConfigService {
24
+ db;
25
+ workspaceService;
22
26
  configDir;
23
27
  agentsPath;
24
- constructor() {
28
+ constructor(db, workspaceService) {
29
+ this.db = db;
30
+ this.workspaceService = workspaceService;
25
31
  const homeDir = process.env.HOME || process.env.USERPROFILE || homedir();
26
32
  this.configDir = join(homeDir, '.openbot', 'desktop');
27
33
  this.agentsPath = join(this.configDir, 'agents.json');
@@ -202,10 +208,14 @@ let AgentConfigService = class AgentConfigService {
202
208
  }
203
209
  if (updates.openclawx !== undefined)
204
210
  agent.openclawx = updates.openclawx;
211
+ if (updates.opencode !== undefined)
212
+ agent.opencode = updates.opencode;
213
+ if (updates.useLongMemory !== undefined)
214
+ agent.useLongMemory = updates.useLongMemory;
205
215
  await this.writeAgentsFile(file);
206
216
  return { ...agent, isDefault: agent.id === DEFAULT_AGENT_ID };
207
217
  }
208
- async deleteAgent(id) {
218
+ async deleteAgent(id, options) {
209
219
  if (id === DEFAULT_AGENT_ID) {
210
220
  throw new BadRequestException('主智能体(default)不可删除');
211
221
  }
@@ -214,8 +224,24 @@ let AgentConfigService = class AgentConfigService {
214
224
  if (idx < 0) {
215
225
  throw new NotFoundException('智能体不存在');
216
226
  }
227
+ const agent = file.agents[idx];
228
+ const workspace = (agent.workspace || agent.id || '').trim();
217
229
  file.agents.splice(idx, 1);
218
230
  await this.writeAgentsFile(file);
231
+ if (workspace && workspace !== DEFAULT_AGENT_ID) {
232
+ this.deleteWorkspaceDataFromDb(workspace);
233
+ }
234
+ if (options?.deleteWorkspaceDir && workspace && workspace !== DEFAULT_AGENT_ID) {
235
+ await this.workspaceService.deleteWorkspaceDirectory(workspace);
236
+ }
237
+ }
238
+ /** 仅删除数据库中与该工作区相关的数据(会话、定时任务、收藏等),不删磁盘目录 */
239
+ deleteWorkspaceDataFromDb(workspace) {
240
+ this.db.run('DELETE FROM token_usage WHERE session_id IN (SELECT id FROM sessions WHERE workspace = ?)', [workspace]);
241
+ this.db.run('DELETE FROM sessions WHERE workspace = ?', [workspace]);
242
+ this.db.run('DELETE FROM scheduled_tasks WHERE workspace = ?', [workspace]);
243
+ this.db.run('DELETE FROM saved_items WHERE workspace = ?', [workspace]);
244
+ this.db.persist();
219
245
  }
220
246
  /**
221
247
  * 根据 config 的 defaultProvider / defaultModel / defaultModelItemCode 及 configuredModels 同步 agents.json 中缺省智能体的 provider、model、modelItemCode。
@@ -258,6 +284,7 @@ let AgentConfigService = class AgentConfigService {
258
284
  };
259
285
  AgentConfigService = __decorate([
260
286
  Injectable(),
261
- __metadata("design:paramtypes", [])
287
+ __metadata("design:paramtypes", [DatabaseService,
288
+ WorkspaceService])
262
289
  ], AgentConfigService);
263
290
  export { AgentConfigService };
@@ -146,7 +146,7 @@ let AgentsService = class AgentsService {
146
146
  if (result.changes > 0) {
147
147
  this.db.persist();
148
148
  }
149
- agentManager.deleteSessionsByBusinessId(sessionId);
149
+ await agentManager.deleteSessionsByBusinessId(sessionId);
150
150
  }
151
151
  getMessageHistory(sessionId) {
152
152
  const rows = this.db.all('SELECT * FROM chat_messages WHERE session_id = ? ORDER BY timestamp ASC', [sessionId]);
@@ -4,7 +4,9 @@
4
4
  * - 独立:设置 globalPrefix('server-api') 并 listen(port),用于单独启动 Desktop Server。
5
5
  */
6
6
  import { NestFactory } from '@nestjs/core';
7
+ import express from 'express';
7
8
  import { AppModule } from './app.module.js';
9
+ const BODY_LIMIT = '10mb';
8
10
  /**
9
11
  * 创建 Nest 应用(内嵌模式):不 listen,不设置 globalPrefix。
10
12
  * Gateway 将返回的 express 挂到 /server-api,请求路径会剥掉前缀后进入 Nest。
@@ -13,13 +15,15 @@ export async function createNestAppEmbedded() {
13
15
  const app = await NestFactory.create(AppModule, {
14
16
  cors: true,
15
17
  });
18
+ const expressApp = app.getHttpAdapter().getInstance();
19
+ expressApp.use(express.json({ limit: BODY_LIMIT }));
20
+ expressApp.use(express.urlencoded({ extended: true, limit: BODY_LIMIT }));
16
21
  app.enableCors({
17
22
  origin: ['http://localhost:5173', 'http://localhost:38080', 'http://localhost:38081'],
18
23
  credentials: true,
19
24
  });
20
25
  await app.init();
21
- const express = app.getHttpAdapter().getInstance();
22
- return { app, express };
26
+ return { app, express: expressApp };
23
27
  }
24
28
  /**
25
29
  * 独立启动时使用:设置 globalPrefix 并监听端口。
@@ -28,6 +32,9 @@ export async function createNestAppStandalone(port = 38081) {
28
32
  const app = await NestFactory.create(AppModule, {
29
33
  cors: true,
30
34
  });
35
+ const expressApp = app.getHttpAdapter().getInstance();
36
+ expressApp.use(express.json({ limit: BODY_LIMIT }));
37
+ expressApp.use(express.urlencoded({ extended: true, limit: BODY_LIMIT }));
31
38
  app.setGlobalPrefix('server-api');
32
39
  app.enableCors({
33
40
  origin: ['http://localhost:5173', 'http://localhost:38080', 'http://localhost:38081'],
@@ -16,15 +16,27 @@ export declare class ConfigController {
16
16
  loginUsername?: string;
17
17
  providers: {
18
18
  [key: string]: {
19
- apiKey?: string;
19
+ apiKey? /** OpenCode 免费/推荐模型列表,供代理配置界面下拉选择(本地/远程模式默认模型) */: string;
20
20
  baseUrl?: string;
21
21
  alias?: string;
22
22
  };
23
23
  };
24
24
  configuredModels?: import("./config.service.js").ConfiguredModelItem[];
25
25
  rag?: {
26
+ embeddingSource?: "local" | "online";
27
+ embeddingModelItemCode?: string;
28
+ localModelPath?: string;
26
29
  embeddingProvider?: string;
27
30
  embeddingModel?: string;
31
+ vectorStore?: "local" | "qdrant";
32
+ qdrant?: {
33
+ url: string;
34
+ apiKey?: string;
35
+ collection?: string;
36
+ };
37
+ };
38
+ memory?: {
39
+ embeddingModelItemCode?: string;
28
40
  };
29
41
  channels?: import("../../core/config/desktop-config.js").ChannelsConfig;
30
42
  };
@@ -43,15 +55,27 @@ export declare class ConfigController {
43
55
  loginUsername?: string;
44
56
  providers: {
45
57
  [key: string]: {
46
- apiKey?: string;
58
+ apiKey? /** OpenCode 免费/推荐模型列表,供代理配置界面下拉选择(本地/远程模式默认模型) */: string;
47
59
  baseUrl?: string;
48
60
  alias?: string;
49
61
  };
50
62
  };
51
63
  configuredModels?: import("./config.service.js").ConfiguredModelItem[];
52
64
  rag?: {
65
+ embeddingSource?: "local" | "online";
66
+ embeddingModelItemCode?: string;
67
+ localModelPath?: string;
53
68
  embeddingProvider?: string;
54
69
  embeddingModel?: string;
70
+ vectorStore?: "local" | "qdrant";
71
+ qdrant?: {
72
+ url: string;
73
+ apiKey?: string;
74
+ collection?: string;
75
+ };
76
+ };
77
+ memory?: {
78
+ embeddingModelItemCode?: string;
55
79
  };
56
80
  channels?: import("../../core/config/desktop-config.js").ChannelsConfig;
57
81
  };
@@ -72,4 +96,9 @@ export declare class ConfigController {
72
96
  types?: string[];
73
97
  }[];
74
98
  }>;
99
+ /** OpenCode 免费/推荐模型列表,供代理配置界面下拉选择(本地/远程模式默认模型) */
100
+ getOpencodeFreeModels(): {
101
+ success: boolean;
102
+ data: import("../../core/agent/proxy/adapters/opencode-free-models.js").OpenCodeFreeModelOption[];
103
+ };
75
104
  }
@@ -11,6 +11,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
11
  return function (target, key) { decorator(target, key, paramIndex); }
12
12
  };
13
13
  import { Controller, Get, Put, Body, Param, Query } from '@nestjs/common';
14
+ import { OPENCODE_FREE_MODELS } from '../../core/agent/proxy/adapters/opencode-free-models.js';
14
15
  import { ConfigService } from './config.service.js';
15
16
  let ConfigController = class ConfigController {
16
17
  configService;
@@ -54,6 +55,13 @@ let ConfigController = class ConfigController {
54
55
  data: models,
55
56
  };
56
57
  }
58
+ /** OpenCode 免费/推荐模型列表,供代理配置界面下拉选择(本地/远程模式默认模型) */
59
+ getOpencodeFreeModels() {
60
+ return {
61
+ success: true,
62
+ data: OPENCODE_FREE_MODELS,
63
+ };
64
+ }
57
65
  };
58
66
  __decorate([
59
67
  Get(),
@@ -88,6 +96,12 @@ __decorate([
88
96
  __metadata("design:paramtypes", [String, String]),
89
97
  __metadata("design:returntype", Promise)
90
98
  ], ConfigController.prototype, "getModels", null);
99
+ __decorate([
100
+ Get('opencode-free-models'),
101
+ __metadata("design:type", Function),
102
+ __metadata("design:paramtypes", []),
103
+ __metadata("design:returntype", void 0)
104
+ ], ConfigController.prototype, "getOpencodeFreeModels", null);
91
105
  ConfigController = __decorate([
92
106
  Controller('config'),
93
107
  __metadata("design:paramtypes", [ConfigService])
@@ -4,7 +4,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
4
4
  else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
5
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6
6
  };
7
- import { Module } from '@nestjs/common';
7
+ import { Module, forwardRef } from '@nestjs/common';
8
8
  import { ConfigController } from './config.controller.js';
9
9
  import { ConfigService } from './config.service.js';
10
10
  import { AgentConfigModule } from '../agent-config/agent-config.module.js';
@@ -12,7 +12,7 @@ let ConfigModule = class ConfigModule {
12
12
  };
13
13
  ConfigModule = __decorate([
14
14
  Module({
15
- imports: [AgentConfigModule],
15
+ imports: [forwardRef(() => AgentConfigModule)],
16
16
  controllers: [ConfigController],
17
17
  providers: [ConfigService],
18
18
  exports: [ConfigService],
@@ -51,10 +51,23 @@ export interface AppConfig {
51
51
  };
52
52
  /** 已配置的模型列表(备用),从该列表中选一个为缺省模型 */
53
53
  configuredModels?: ConfiguredModelItem[];
54
- /** RAG 知识库:embedding 使用该 provider+model,未配置时基于 RAG 的长记忆空转 */
54
+ /** RAG 知识库:向量模型(本地/在线)+ 向量库(本地/远程 Qdrant) */
55
55
  rag?: {
56
+ embeddingSource?: 'local' | 'online';
57
+ embeddingModelItemCode?: string;
58
+ localModelPath?: string;
56
59
  embeddingProvider?: string;
57
60
  embeddingModel?: string;
61
+ vectorStore?: 'local' | 'qdrant';
62
+ qdrant?: {
63
+ url: string;
64
+ apiKey?: string;
65
+ collection?: string;
66
+ };
67
+ };
68
+ /** Memory 记忆库:为 Agent 提供默认嵌入模型 */
69
+ memory?: {
70
+ embeddingModelItemCode?: string;
58
71
  };
59
72
  /** 通道配置:飞书、Telegram 等 token/key */
60
73
  channels?: ChannelsConfig;
@@ -41,6 +41,7 @@ let ConfigService = class ConfigService {
41
41
  providers: {},
42
42
  configuredModels: [],
43
43
  rag: undefined,
44
+ memory: {},
44
45
  channels: {},
45
46
  };
46
47
  }
@@ -1,3 +1,5 @@
1
+ /** 主智能体对应工作区名,禁止删除其目录 */
2
+ export declare const DEFAULT_WORKSPACE_NAME = "default";
1
3
  export interface WorkspaceItem {
2
4
  name: string;
3
5
  path: string;
@@ -19,6 +21,11 @@ export declare class WorkspaceService {
19
21
  absolutePath: string;
20
22
  safe: boolean;
21
23
  };
24
+ /**
25
+ * 删除整个工作区目录(磁盘)。禁止删除 default 工作区。
26
+ * 仅当调用方确认需物理删除时使用(如删除智能体时用户勾选「同时删除工作区目录」)。
27
+ */
28
+ deleteWorkspaceDirectory(workspaceName: string): Promise<void>;
22
29
  /** Delete a file or directory (recursive) under workspace. Returns true if deleted. skills 与 .skills 目录禁止删除。 */
23
30
  deletePath(workspaceName: string, relativePath: string): Promise<boolean>;
24
31
  private safeRelativePath;
@@ -10,6 +10,8 @@ import { join, resolve, relative } from 'path';
10
10
  import { existsSync } from 'fs';
11
11
  import { homedir } from 'os';
12
12
  import { getOpenbotWorkspaceDir } from '../../core/agent/agent-dir.js';
13
+ /** 主智能体对应工作区名,禁止删除其目录 */
14
+ export const DEFAULT_WORKSPACE_NAME = 'default';
13
15
  let WorkspaceService = class WorkspaceService {
14
16
  getWorkspaceRoot(name) {
15
17
  return join(getOpenbotWorkspaceDir(), name);
@@ -78,6 +80,20 @@ let WorkspaceService = class WorkspaceService {
78
80
  const ok = resolve(absolute).startsWith(root) && existsSync(absolute);
79
81
  return { absolutePath: absolute, safe: ok };
80
82
  }
83
+ /**
84
+ * 删除整个工作区目录(磁盘)。禁止删除 default 工作区。
85
+ * 仅当调用方确认需物理删除时使用(如删除智能体时用户勾选「同时删除工作区目录」)。
86
+ */
87
+ async deleteWorkspaceDirectory(workspaceName) {
88
+ const name = (workspaceName || '').trim();
89
+ if (name === '' || name === DEFAULT_WORKSPACE_NAME) {
90
+ throw new Error('不能删除 default 工作区目录');
91
+ }
92
+ const root = resolve(this.getWorkspaceRoot(name));
93
+ if (!existsSync(root))
94
+ return;
95
+ await rm(root, { recursive: true });
96
+ }
81
97
  /** Delete a file or directory (recursive) under workspace. Returns true if deleted. skills 与 .skills 目录禁止删除。 */
82
98
  async deletePath(workspaceName, relativePath) {
83
99
  const safe = this.safeRelativePath(relativePath);
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "publishConfig": {
4
4
  "access": "public"
5
5
  },
6
- "version": "0.8.17",
6
+ "version": "0.8.26",
7
7
  "description": "OpenClawX - A professional desktop application for managing and executing AI agents with real-time chat, session management, and skills browsing.",
8
8
  "type": "module",
9
9
  "main": "dist/index.js",
@@ -33,6 +33,7 @@
33
33
  "@nestjs/platform-express": "^10.3.0",
34
34
  "@nestjs/platform-socket.io": "^10.3.0",
35
35
  "@nestjs/websockets": "^10.3.0",
36
+ "@opencode-ai/sdk": "^1.2.10",
36
37
  "@sinclair/typebox": "^0.34.41",
37
38
  "adm-zip": "^0.5.16",
38
39
  "agent-browser": "^0.8.5",
@@ -40,10 +41,13 @@
40
41
  "croner": "^9.1.0",
41
42
  "dingtalk-stream": "^2.1.4",
42
43
  "multer": "^1.4.5-lts.1",
44
+ "node-llama-cpp": "^3.15.0",
45
+ "qrcode": "^1.5.4",
43
46
  "reflect-metadata": "^0.2.1",
44
47
  "rxjs": "^7.8.1",
45
48
  "sql.js": "^1.13.0",
46
49
  "vectra": "^0.12.3",
50
+ "wechaty": "^1.20.2",
47
51
  "ws": "^8.19.0"
48
52
  },
49
53
  "devDependencies": {
@@ -53,6 +57,7 @@
53
57
  "@types/jest": "^29.5.14",
54
58
  "@types/multer": "^2.0.0",
55
59
  "@types/node": "^22.0.0",
60
+ "@types/qrcode": "^1.5.6",
56
61
  "@types/sql.js": "^1.4.9",
57
62
  "@types/ws": "^8.18.1",
58
63
  "jest": "^29.7.0",