@next-open-ai/openclawx 0.6.6

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 (198) hide show
  1. package/README.md +523 -0
  2. package/apps/desktop/README.md +210 -0
  3. package/apps/desktop/renderer/dist/assets/index-CYkSfhcp.css +10 -0
  4. package/apps/desktop/renderer/dist/assets/index-FI6O25Ms.js +89 -0
  5. package/apps/desktop/renderer/dist/index.html +22 -0
  6. package/dist/cli/cli.d.ts +2 -0
  7. package/dist/cli/cli.js +198 -0
  8. package/dist/cli/service.d.ts +13 -0
  9. package/dist/cli/service.js +243 -0
  10. package/dist/cli.d.ts +5 -0
  11. package/dist/cli.js +5 -0
  12. package/dist/core/agent/agent-dir.d.ts +14 -0
  13. package/dist/core/agent/agent-dir.js +75 -0
  14. package/dist/core/agent/agent-manager.d.ts +64 -0
  15. package/dist/core/agent/agent-manager.js +278 -0
  16. package/dist/core/agent/config-manager.d.ts +25 -0
  17. package/dist/core/agent/config-manager.js +84 -0
  18. package/dist/core/agent/run.d.ts +26 -0
  19. package/dist/core/agent/run.js +65 -0
  20. package/dist/core/agent/skills.d.ts +20 -0
  21. package/dist/core/agent/skills.js +86 -0
  22. package/dist/core/config/desktop-config.d.ts +90 -0
  23. package/dist/core/config/desktop-config.js +521 -0
  24. package/dist/core/config/provider-support-default.d.ts +21 -0
  25. package/dist/core/config/provider-support-default.js +57 -0
  26. package/dist/core/installer/index.d.ts +1 -0
  27. package/dist/core/installer/index.js +1 -0
  28. package/dist/core/installer/skill-installer.d.ts +39 -0
  29. package/dist/core/installer/skill-installer.js +215 -0
  30. package/dist/core/mcp/adapter.d.ts +17 -0
  31. package/dist/core/mcp/adapter.js +49 -0
  32. package/dist/core/mcp/client.d.ts +24 -0
  33. package/dist/core/mcp/client.js +70 -0
  34. package/dist/core/mcp/config.d.ts +22 -0
  35. package/dist/core/mcp/config.js +69 -0
  36. package/dist/core/mcp/index.d.ts +18 -0
  37. package/dist/core/mcp/index.js +20 -0
  38. package/dist/core/mcp/operator.d.ts +15 -0
  39. package/dist/core/mcp/operator.js +72 -0
  40. package/dist/core/mcp/transport/index.d.ts +11 -0
  41. package/dist/core/mcp/transport/index.js +16 -0
  42. package/dist/core/mcp/transport/sse.d.ts +20 -0
  43. package/dist/core/mcp/transport/sse.js +82 -0
  44. package/dist/core/mcp/transport/stdio.d.ts +32 -0
  45. package/dist/core/mcp/transport/stdio.js +132 -0
  46. package/dist/core/mcp/types.d.ts +72 -0
  47. package/dist/core/mcp/types.js +5 -0
  48. package/dist/core/memory/build-summary.d.ts +6 -0
  49. package/dist/core/memory/build-summary.js +27 -0
  50. package/dist/core/memory/compaction-extension.d.ts +6 -0
  51. package/dist/core/memory/compaction-extension.js +23 -0
  52. package/dist/core/memory/embedding.d.ts +4 -0
  53. package/dist/core/memory/embedding.js +15 -0
  54. package/dist/core/memory/index.d.ts +29 -0
  55. package/dist/core/memory/index.js +70 -0
  56. package/dist/core/memory/remote-embedding.d.ts +10 -0
  57. package/dist/core/memory/remote-embedding.js +36 -0
  58. package/dist/core/memory/types.d.ts +16 -0
  59. package/dist/core/memory/types.js +1 -0
  60. package/dist/core/memory/vector-store.d.ts +15 -0
  61. package/dist/core/memory/vector-store.js +65 -0
  62. package/dist/core/tools/bookmark-tool.d.ts +9 -0
  63. package/dist/core/tools/bookmark-tool.js +118 -0
  64. package/dist/core/tools/browser-tool.d.ts +10 -0
  65. package/dist/core/tools/browser-tool.js +362 -0
  66. package/dist/core/tools/index.d.ts +4 -0
  67. package/dist/core/tools/index.js +4 -0
  68. package/dist/core/tools/install-skill-tool.d.ts +6 -0
  69. package/dist/core/tools/install-skill-tool.js +53 -0
  70. package/dist/core/tools/save-experience-tool.d.ts +5 -0
  71. package/dist/core/tools/save-experience-tool.js +54 -0
  72. package/dist/gateway/auth-hooks.d.ts +17 -0
  73. package/dist/gateway/auth-hooks.js +19 -0
  74. package/dist/gateway/backend-url.d.ts +2 -0
  75. package/dist/gateway/backend-url.js +11 -0
  76. package/dist/gateway/channel-handler.d.ts +6 -0
  77. package/dist/gateway/channel-handler.js +3 -0
  78. package/dist/gateway/clients.d.ts +5 -0
  79. package/dist/gateway/clients.js +4 -0
  80. package/dist/gateway/connection-handler.d.ts +6 -0
  81. package/dist/gateway/connection-handler.js +48 -0
  82. package/dist/gateway/index.d.ts +3 -0
  83. package/dist/gateway/index.js +2 -0
  84. package/dist/gateway/message-handler.d.ts +5 -0
  85. package/dist/gateway/message-handler.js +65 -0
  86. package/dist/gateway/methods/agent-cancel.d.ts +10 -0
  87. package/dist/gateway/methods/agent-cancel.js +17 -0
  88. package/dist/gateway/methods/agent-chat.d.ts +8 -0
  89. package/dist/gateway/methods/agent-chat.js +148 -0
  90. package/dist/gateway/methods/connect.d.ts +9 -0
  91. package/dist/gateway/methods/connect.js +18 -0
  92. package/dist/gateway/methods/install-skill-from-path.d.ts +13 -0
  93. package/dist/gateway/methods/install-skill-from-path.js +15 -0
  94. package/dist/gateway/methods/install-skill-from-upload.d.ts +14 -0
  95. package/dist/gateway/methods/install-skill-from-upload.js +13 -0
  96. package/dist/gateway/methods/run-scheduled-task.d.ts +15 -0
  97. package/dist/gateway/methods/run-scheduled-task.js +127 -0
  98. package/dist/gateway/paths.d.ts +20 -0
  99. package/dist/gateway/paths.js +19 -0
  100. package/dist/gateway/server.d.ts +8 -0
  101. package/dist/gateway/server.js +190 -0
  102. package/dist/gateway/sse-handler.d.ts +6 -0
  103. package/dist/gateway/sse-handler.js +3 -0
  104. package/dist/gateway/types.d.ts +90 -0
  105. package/dist/gateway/types.js +1 -0
  106. package/dist/gateway/utils.d.ts +22 -0
  107. package/dist/gateway/utils.js +67 -0
  108. package/dist/gateway/voice-handler.d.ts +12 -0
  109. package/dist/gateway/voice-handler.js +18 -0
  110. package/dist/index.d.ts +5 -0
  111. package/dist/index.js +5 -0
  112. package/dist/server/agent-config/agent-config.controller.d.ts +30 -0
  113. package/dist/server/agent-config/agent-config.controller.js +83 -0
  114. package/dist/server/agent-config/agent-config.module.d.ts +2 -0
  115. package/dist/server/agent-config/agent-config.module.js +19 -0
  116. package/dist/server/agent-config/agent-config.service.d.ts +53 -0
  117. package/dist/server/agent-config/agent-config.service.js +213 -0
  118. package/dist/server/agents/agents.controller.d.ts +41 -0
  119. package/dist/server/agents/agents.controller.js +118 -0
  120. package/dist/server/agents/agents.gateway.d.ts +21 -0
  121. package/dist/server/agents/agents.gateway.js +103 -0
  122. package/dist/server/agents/agents.module.d.ts +2 -0
  123. package/dist/server/agents/agents.module.js +20 -0
  124. package/dist/server/agents/agents.service.d.ts +63 -0
  125. package/dist/server/agents/agents.service.js +169 -0
  126. package/dist/server/app.module.d.ts +2 -0
  127. package/dist/server/app.module.js +38 -0
  128. package/dist/server/auth/auth.controller.d.ts +20 -0
  129. package/dist/server/auth/auth.controller.js +64 -0
  130. package/dist/server/auth/auth.module.d.ts +2 -0
  131. package/dist/server/auth/auth.module.js +19 -0
  132. package/dist/server/bootstrap.d.ts +15 -0
  133. package/dist/server/bootstrap.js +38 -0
  134. package/dist/server/config/config.controller.d.ts +73 -0
  135. package/dist/server/config/config.controller.js +95 -0
  136. package/dist/server/config/config.module.d.ts +2 -0
  137. package/dist/server/config/config.module.js +21 -0
  138. package/dist/server/config/config.service.d.ts +82 -0
  139. package/dist/server/config/config.service.js +123 -0
  140. package/dist/server/database/database.module.d.ts +2 -0
  141. package/dist/server/database/database.module.js +18 -0
  142. package/dist/server/database/database.service.d.ts +26 -0
  143. package/dist/server/database/database.service.js +253 -0
  144. package/dist/server/main.d.ts +1 -0
  145. package/dist/server/main.js +9 -0
  146. package/dist/server/saved-items/saved-items.controller.d.ts +57 -0
  147. package/dist/server/saved-items/saved-items.controller.js +229 -0
  148. package/dist/server/saved-items/saved-items.module.d.ts +2 -0
  149. package/dist/server/saved-items/saved-items.module.js +25 -0
  150. package/dist/server/saved-items/saved-items.service.d.ts +31 -0
  151. package/dist/server/saved-items/saved-items.service.js +105 -0
  152. package/dist/server/saved-items/tags.controller.d.ts +30 -0
  153. package/dist/server/saved-items/tags.controller.js +85 -0
  154. package/dist/server/saved-items/tags.service.d.ts +24 -0
  155. package/dist/server/saved-items/tags.service.js +84 -0
  156. package/dist/server/skills/skills.controller.d.ts +63 -0
  157. package/dist/server/skills/skills.controller.js +194 -0
  158. package/dist/server/skills/skills.module.d.ts +2 -0
  159. package/dist/server/skills/skills.module.js +22 -0
  160. package/dist/server/skills/skills.service.d.ts +65 -0
  161. package/dist/server/skills/skills.service.js +388 -0
  162. package/dist/server/tasks/tasks.controller.d.ts +52 -0
  163. package/dist/server/tasks/tasks.controller.js +163 -0
  164. package/dist/server/tasks/tasks.module.d.ts +2 -0
  165. package/dist/server/tasks/tasks.module.js +23 -0
  166. package/dist/server/tasks/tasks.service.d.ts +86 -0
  167. package/dist/server/tasks/tasks.service.js +327 -0
  168. package/dist/server/usage/usage.controller.d.ts +12 -0
  169. package/dist/server/usage/usage.controller.js +46 -0
  170. package/dist/server/usage/usage.module.d.ts +2 -0
  171. package/dist/server/usage/usage.module.js +19 -0
  172. package/dist/server/usage/usage.service.d.ts +21 -0
  173. package/dist/server/usage/usage.service.js +55 -0
  174. package/dist/server/users/users.controller.d.ts +35 -0
  175. package/dist/server/users/users.controller.js +69 -0
  176. package/dist/server/users/users.module.d.ts +2 -0
  177. package/dist/server/users/users.module.js +19 -0
  178. package/dist/server/users/users.service.d.ts +39 -0
  179. package/dist/server/users/users.service.js +140 -0
  180. package/dist/server/workspace/workspace.controller.d.ts +24 -0
  181. package/dist/server/workspace/workspace.controller.js +132 -0
  182. package/dist/server/workspace/workspace.module.d.ts +2 -0
  183. package/dist/server/workspace/workspace.module.js +21 -0
  184. package/dist/server/workspace/workspace.service.d.ts +36 -0
  185. package/dist/server/workspace/workspace.service.js +142 -0
  186. package/package.json +90 -0
  187. package/skills/agent-browser/SKILL.md +207 -0
  188. package/skills/agent-browser/references/authentication.md +202 -0
  189. package/skills/agent-browser/references/commands.md +259 -0
  190. package/skills/agent-browser/references/proxy-support.md +188 -0
  191. package/skills/agent-browser/references/session-management.md +193 -0
  192. package/skills/agent-browser/references/snapshot-refs.md +194 -0
  193. package/skills/agent-browser/references/video-recording.md +173 -0
  194. package/skills/agent-browser/templates/authenticated-session.sh +97 -0
  195. package/skills/agent-browser/templates/capture-workflow.sh +69 -0
  196. package/skills/agent-browser/templates/form-automation.sh +62 -0
  197. package/skills/find-skills/SKILL.md +140 -0
  198. package/skills/url-bookmark/SKILL.md +36 -0
@@ -0,0 +1,521 @@
1
+ /**
2
+ * 桌面端配置单一入口(~/.openbot/desktop)。
3
+ * 供 CLI、WebSocket Gateway 等读取与写入,与 Nest Desktop Backend 使用的 config.json / agents.json 一致。
4
+ * provider-support.json 提供流行 provider 及模型目录,供配置时下拉备选;配置完成后可同步到 agent 目录 models.json 供 pi 使用。
5
+ */
6
+ import { readFile, writeFile } from "fs/promises";
7
+ import { readFileSync, existsSync, mkdirSync } from "fs";
8
+ import { join } from "path";
9
+ import { homedir } from "os";
10
+ import { getOpenbotAgentDir } from "../agent/agent-dir.js";
11
+ import { DEFAULT_PROVIDER_SUPPORT, } from "./provider-support-default.js";
12
+ function getDesktopDir() {
13
+ const home = process.env.HOME || process.env.USERPROFILE || homedir();
14
+ return join(home, ".openbot", "desktop");
15
+ }
16
+ const DEFAULT_AGENT_ID = "default";
17
+ const DEFAULT_MAX_AGENT_SESSIONS = 5;
18
+ /** 同步读取桌面全局配置(Gateway 等需要同步读的场景) */
19
+ function getConfigPath() {
20
+ return join(getDesktopDir(), "config.json");
21
+ }
22
+ const PROVIDER_SUPPORT_FILENAME = "provider-support.json";
23
+ function getProviderSupportPath() {
24
+ return join(getDesktopDir(), PROVIDER_SUPPORT_FILENAME);
25
+ }
26
+ /**
27
+ * 同步读取桌面全局配置中的 maxAgentSessions 等。
28
+ * Gateway 进程内使用,用于会话上限等。
29
+ */
30
+ export function getDesktopConfig() {
31
+ try {
32
+ const configPath = getConfigPath();
33
+ if (!existsSync(configPath)) {
34
+ return { maxAgentSessions: DEFAULT_MAX_AGENT_SESSIONS };
35
+ }
36
+ const content = readFileSync(configPath, "utf-8");
37
+ const data = JSON.parse(content);
38
+ const max = data.maxAgentSessions;
39
+ const maxAgentSessions = typeof max === "number" && max > 0 ? Math.floor(max) : DEFAULT_MAX_AGENT_SESSIONS;
40
+ return { maxAgentSessions };
41
+ }
42
+ catch {
43
+ return { maxAgentSessions: DEFAULT_MAX_AGENT_SESSIONS };
44
+ }
45
+ }
46
+ /** 同步读取 RAG embedding 配置;未配置或无效时返回 null,长记忆将空转 */
47
+ export function getRagEmbeddingConfigSync() {
48
+ try {
49
+ const configPath = getConfigPath();
50
+ if (!existsSync(configPath))
51
+ return null;
52
+ const content = readFileSync(configPath, "utf-8");
53
+ const data = JSON.parse(content);
54
+ const provider = data.rag?.embeddingProvider?.trim();
55
+ const modelId = data.rag?.embeddingModel?.trim();
56
+ if (!provider || !modelId)
57
+ return null;
58
+ const prov = data.providers?.[provider];
59
+ const apiKey = prov?.apiKey?.trim();
60
+ if (!apiKey)
61
+ return null;
62
+ let baseUrl = prov?.baseUrl?.trim();
63
+ if (!baseUrl) {
64
+ const d = EMBEDDING_DEFAULT_BASE_URL[provider];
65
+ baseUrl = d ?? "";
66
+ }
67
+ if (!baseUrl)
68
+ return null;
69
+ return { provider, modelId, apiKey, baseUrl: baseUrl.replace(/\/$/, "") };
70
+ }
71
+ catch {
72
+ return null;
73
+ }
74
+ }
75
+ const EMBEDDING_DEFAULT_BASE_URL = {
76
+ openai: "https://api.openai.com/v1",
77
+ "openai-custom": "",
78
+ deepseek: "https://api.deepseek.com/v1",
79
+ dashscope: "https://dashscope.aliyuncs.com/compatible-mode/v1",
80
+ nvidia: "https://integrate.api.nvidia.com/v1",
81
+ kimi: "https://api.moonshot.cn/v1",
82
+ };
83
+ /**
84
+ * 从 config.json 读取缺省智能体 id(defaultAgentId)。
85
+ * 若未配置、或该 id 在 agents.json 中不存在,则返回 default。
86
+ */
87
+ export async function getBoundAgentIdForCli() {
88
+ const desktopDir = getDesktopDir();
89
+ const configPath = join(desktopDir, "config.json");
90
+ const agentsPath = join(desktopDir, "agents.json");
91
+ let boundId = DEFAULT_AGENT_ID;
92
+ if (existsSync(configPath)) {
93
+ try {
94
+ const raw = await readFile(configPath, "utf-8");
95
+ const config = JSON.parse(raw);
96
+ const id = config.defaultAgentId ? String(config.defaultAgentId).trim() : "";
97
+ if (id)
98
+ boundId = id;
99
+ }
100
+ catch {
101
+ // ignore, use default
102
+ }
103
+ }
104
+ if (boundId === DEFAULT_AGENT_ID)
105
+ return DEFAULT_AGENT_ID;
106
+ if (!existsSync(agentsPath))
107
+ return DEFAULT_AGENT_ID;
108
+ try {
109
+ const raw = await readFile(agentsPath, "utf-8");
110
+ const data = JSON.parse(raw);
111
+ const agents = Array.isArray(data.agents) ? data.agents : [];
112
+ const found = agents.some((a) => a.id === boundId);
113
+ return found ? boundId : DEFAULT_AGENT_ID;
114
+ }
115
+ catch {
116
+ return DEFAULT_AGENT_ID;
117
+ }
118
+ }
119
+ /**
120
+ * 根据 agentId 从桌面配置中读取该 agent 的 provider、model 及 API Key。
121
+ * 若文件不存在或解析失败返回 null,调用方使用环境变量或默认值。
122
+ */
123
+ export async function loadDesktopAgentConfig(agentId) {
124
+ const desktopDir = getDesktopDir();
125
+ const configPath = join(desktopDir, "config.json");
126
+ const agentsPath = join(desktopDir, "agents.json");
127
+ let config = {};
128
+ if (existsSync(configPath)) {
129
+ try {
130
+ const raw = await readFile(configPath, "utf-8");
131
+ config = JSON.parse(raw);
132
+ }
133
+ catch {
134
+ return null;
135
+ }
136
+ }
137
+ const resolvedAgentId = agentId === "default" ? "default" : agentId;
138
+ let provider = config.defaultProvider ?? "deepseek";
139
+ let model = config.defaultModel ?? "deepseek-chat";
140
+ if (config.defaultModelItemCode && Array.isArray(config.configuredModels)) {
141
+ const configured = config.configuredModels.find((m) => m.modelItemCode === config.defaultModelItemCode);
142
+ if (configured) {
143
+ provider = configured.provider;
144
+ model = configured.modelId;
145
+ }
146
+ }
147
+ let workspaceName = resolvedAgentId;
148
+ let mcpServers;
149
+ if (existsSync(agentsPath)) {
150
+ try {
151
+ const raw = await readFile(agentsPath, "utf-8");
152
+ const data = JSON.parse(raw);
153
+ const agents = Array.isArray(data.agents) ? data.agents : [];
154
+ const agent = agents.find((a) => a.id === resolvedAgentId);
155
+ if (agent) {
156
+ if (agent.workspace)
157
+ workspaceName = agent.workspace;
158
+ else if (agent.id)
159
+ workspaceName = agent.id;
160
+ if (agent.mcpServers && Array.isArray(agent.mcpServers)) {
161
+ mcpServers = agent.mcpServers;
162
+ }
163
+ if (agent.modelItemCode && Array.isArray(config.configuredModels)) {
164
+ const configured = config.configuredModels.find((m) => m.modelItemCode === agent.modelItemCode);
165
+ if (configured) {
166
+ provider = configured.provider;
167
+ model = configured.modelId;
168
+ }
169
+ else {
170
+ if (agent.provider)
171
+ provider = agent.provider;
172
+ if (agent.model)
173
+ model = agent.model;
174
+ }
175
+ }
176
+ else {
177
+ if (agent.provider)
178
+ provider = agent.provider;
179
+ if (agent.model)
180
+ model = agent.model;
181
+ }
182
+ }
183
+ }
184
+ catch {
185
+ // ignore
186
+ }
187
+ }
188
+ const provConfig = config.providers?.[provider];
189
+ const apiKey = provConfig?.apiKey && typeof provConfig.apiKey === "string" && provConfig.apiKey.trim()
190
+ ? provConfig.apiKey.trim()
191
+ : undefined;
192
+ return { provider, model, apiKey: apiKey ?? undefined, workspace: workspaceName, mcpServers };
193
+ }
194
+ function ensureDesktopDir() {
195
+ const desktopDir = getDesktopDir();
196
+ if (!existsSync(desktopDir)) {
197
+ mkdirSync(desktopDir, { recursive: true });
198
+ }
199
+ return desktopDir;
200
+ }
201
+ async function readDesktopConfigJson() {
202
+ const configPath = getConfigPath();
203
+ if (!existsSync(configPath))
204
+ return {};
205
+ try {
206
+ const raw = await readFile(configPath, "utf-8");
207
+ return JSON.parse(raw);
208
+ }
209
+ catch {
210
+ return {};
211
+ }
212
+ }
213
+ async function writeDesktopConfigJson(config) {
214
+ ensureDesktopDir();
215
+ const configPath = getConfigPath();
216
+ await writeFile(configPath, JSON.stringify(config, null, 2), "utf-8");
217
+ }
218
+ /**
219
+ * 将某 provider 的 API Key 写入桌面 config(中心化配置源)。
220
+ * openbot login 使用:缺省 alias 与 provider 同名;若有 baseUrl 则一并写入。
221
+ * 若传入 modelId 或未传则取该 provider 第一个模型,会补齐 defaultProvider/defaultModel、configuredModels、agents 默认智能体,后续可直接运行。
222
+ */
223
+ export async function setProviderApiKey(provider, apiKey, modelId) {
224
+ const config = await readDesktopConfigJson();
225
+ if (!config.providers)
226
+ config.providers = {};
227
+ if (!config.providers[provider])
228
+ config.providers[provider] = {};
229
+ const entry = config.providers[provider];
230
+ entry.apiKey = apiKey.trim();
231
+ if (entry.alias === undefined || entry.alias === "")
232
+ entry.alias = provider;
233
+ const support = await getProviderSupport();
234
+ const supportEntry = support[provider];
235
+ if (supportEntry?.baseUrl != null && String(supportEntry.baseUrl).trim() !== "" && !(entry.baseUrl != null && String(entry.baseUrl).trim() !== "")) {
236
+ entry.baseUrl = supportEntry.baseUrl.trim();
237
+ }
238
+ await writeDesktopConfigJson(config);
239
+ const effectiveModelId = (modelId != null && String(modelId).trim() !== "")
240
+ ? String(modelId).trim()
241
+ : await getFirstModelForProvider(provider);
242
+ if (effectiveModelId) {
243
+ await setDefaultModel(provider, effectiveModelId);
244
+ }
245
+ else {
246
+ await syncDesktopConfigToModelsJson();
247
+ }
248
+ }
249
+ /** 生成 configuredModels 项的 modelItemCode,与界面约定一致 */
250
+ function buildModelItemCode(provider, modelId) {
251
+ return `${provider}_${modelId}`.replace(/[^a-zA-Z0-9_-]/g, "_");
252
+ }
253
+ /**
254
+ * 将全局默认 provider/model 写入桌面 config,并在 configuredModels 中增加/更新对应项,agents.json 中缺省智能体写入 modelItemCode。
255
+ * openbot config set-model 使用此方法。
256
+ */
257
+ export async function setDefaultModel(provider, modelId) {
258
+ const modelIdTrim = modelId.trim();
259
+ const modelItemCode = buildModelItemCode(provider, modelIdTrim);
260
+ const config = await readDesktopConfigJson();
261
+ config.defaultProvider = provider;
262
+ config.defaultModel = modelIdTrim;
263
+ config.defaultModelItemCode = modelItemCode;
264
+ if (!Array.isArray(config.configuredModels))
265
+ config.configuredModels = [];
266
+ const list = config.configuredModels;
267
+ const existing = list.find((m) => m.modelItemCode === modelItemCode || (m.provider === provider && m.modelId === modelIdTrim));
268
+ const item = {
269
+ provider,
270
+ modelId: modelIdTrim,
271
+ type: "llm",
272
+ alias: `${modelIdTrim} item`,
273
+ modelItemCode,
274
+ reasoning: false,
275
+ cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
276
+ contextWindow: 64000,
277
+ maxTokens: 8192,
278
+ };
279
+ if (existing) {
280
+ Object.assign(existing, item);
281
+ }
282
+ else {
283
+ list.push(item);
284
+ }
285
+ await writeDesktopConfigJson(config);
286
+ const agentsPath = join(getDesktopDir(), "agents.json");
287
+ if (existsSync(agentsPath)) {
288
+ try {
289
+ const raw = await readFile(agentsPath, "utf-8");
290
+ const data = JSON.parse(raw);
291
+ const agents = Array.isArray(data.agents) ? data.agents : [];
292
+ const defaultAgent = agents.find((a) => a.id === DEFAULT_AGENT_ID);
293
+ if (defaultAgent) {
294
+ defaultAgent.provider = provider;
295
+ defaultAgent.model = modelIdTrim;
296
+ defaultAgent.modelItemCode = modelItemCode;
297
+ }
298
+ else {
299
+ agents.unshift({
300
+ id: DEFAULT_AGENT_ID,
301
+ name: "主智能体",
302
+ workspace: DEFAULT_AGENT_ID,
303
+ provider,
304
+ model: modelIdTrim,
305
+ modelItemCode,
306
+ });
307
+ }
308
+ await writeFile(agentsPath, JSON.stringify({ agents }, null, 2), "utf-8");
309
+ }
310
+ catch {
311
+ // ignore
312
+ }
313
+ }
314
+ await syncDesktopConfigToModelsJson();
315
+ }
316
+ /**
317
+ * 供 CLI config list 使用,从桌面 config 读出配置列表。
318
+ */
319
+ export async function getDesktopConfigList() {
320
+ const config = await readDesktopConfigJson();
321
+ const defaultProvider = config.defaultProvider ?? "deepseek";
322
+ const defaultModel = config.defaultModel ?? "deepseek-chat";
323
+ const providers = config.providers ?? {};
324
+ const entries = Object.entries(providers).map(([name, p]) => ({
325
+ provider: name,
326
+ defaultModel: name === defaultProvider ? defaultModel : "—",
327
+ hasKey: !!(p?.apiKey && String(p.apiKey).trim()),
328
+ }));
329
+ if (entries.length === 0) {
330
+ entries.push({
331
+ provider: defaultProvider,
332
+ defaultModel,
333
+ hasKey: false,
334
+ });
335
+ }
336
+ return { defaultProvider, defaultModel, defaultModelItemCode: config.defaultModelItemCode, providers: entries };
337
+ }
338
+ /**
339
+ * 确保桌面目录下存在 provider-support.json(不存在则写入默认内容)。
340
+ * 供配置供应商时作备选下拉列表项。
341
+ */
342
+ export async function ensureProviderSupportFile() {
343
+ const path = getProviderSupportPath();
344
+ if (existsSync(path))
345
+ return;
346
+ ensureDesktopDir();
347
+ await writeFile(path, JSON.stringify(DEFAULT_PROVIDER_SUPPORT, null, 2), "utf-8");
348
+ }
349
+ /** 若 config.json 不存在则写入默认结构,供 CLI/Gateway 启动时初始化 */
350
+ async function ensureConfigJsonInitialized() {
351
+ const configPath = getConfigPath();
352
+ if (existsSync(configPath))
353
+ return;
354
+ ensureDesktopDir();
355
+ const defaultConfig = {
356
+ defaultProvider: "deepseek",
357
+ defaultModel: "deepseek-chat",
358
+ defaultAgentId: DEFAULT_AGENT_ID,
359
+ maxAgentSessions: DEFAULT_MAX_AGENT_SESSIONS,
360
+ providers: {},
361
+ configuredModels: [],
362
+ };
363
+ await writeFile(configPath, JSON.stringify(defaultConfig, null, 2), "utf-8");
364
+ }
365
+ /** 若 agents.json 不存在则写入默认智能体,供 CLI/Gateway 启动时初始化 */
366
+ async function ensureAgentsJsonInitialized() {
367
+ const agentsPath = join(getDesktopDir(), "agents.json");
368
+ if (existsSync(agentsPath))
369
+ return;
370
+ ensureDesktopDir();
371
+ const defaultAgents = {
372
+ agents: [
373
+ { id: DEFAULT_AGENT_ID, name: "主智能体", workspace: DEFAULT_AGENT_ID },
374
+ ],
375
+ };
376
+ await writeFile(agentsPath, JSON.stringify(defaultAgents, null, 2), "utf-8");
377
+ }
378
+ /**
379
+ * CLI / Gateway 运行时调用,确保 config.json、provider-support.json、agents.json 均完成初始化。
380
+ */
381
+ export async function ensureDesktopConfigInitialized() {
382
+ ensureDesktopDir();
383
+ await ensureProviderSupportFile();
384
+ await ensureConfigJsonInitialized();
385
+ await ensureAgentsJsonInitialized();
386
+ }
387
+ /**
388
+ * 取某 provider 在 provider-support 中的第一个 llm 模型 id;若无则返回第一个模型 id。
389
+ */
390
+ export async function getFirstModelForProvider(provider) {
391
+ const support = await getProviderSupport();
392
+ const entry = support[provider];
393
+ if (!entry?.models?.length)
394
+ return null;
395
+ const llm = entry.models.find((m) => m.types?.includes("llm"));
396
+ if (llm)
397
+ return llm.id;
398
+ return entry.models[0].id;
399
+ }
400
+ /**
401
+ * 读取桌面 provider-support.json(流行 provider 及模型目录)。
402
+ * 若文件不存在则先写入默认内容再返回;若存在则与默认合并,补全默认中已有而文件中缺失的 provider(如新增的 openai-custom)。
403
+ */
404
+ export async function getProviderSupport() {
405
+ await ensureProviderSupportFile();
406
+ const path = getProviderSupportPath();
407
+ try {
408
+ const raw = await readFile(path, "utf-8");
409
+ const fromFile = JSON.parse(raw);
410
+ const merged = { ...fromFile };
411
+ let hasNew = false;
412
+ for (const [id, entry] of Object.entries(DEFAULT_PROVIDER_SUPPORT)) {
413
+ if (!(id in merged)) {
414
+ merged[id] = entry;
415
+ hasNew = true;
416
+ }
417
+ }
418
+ if (hasNew) {
419
+ await writeFile(path, JSON.stringify(merged, null, 2), "utf-8");
420
+ }
421
+ return merged;
422
+ }
423
+ catch {
424
+ return DEFAULT_PROVIDER_SUPPORT;
425
+ }
426
+ }
427
+ /** 同步到 pi models.json 时使用的默认 baseUrl / apiKey 环境变量名 / api,provider-support 中不再存储 */
428
+ const SYNC_DEFAULTS = {
429
+ deepseek: { baseUrl: "https://api.deepseek.com", apiKey: "OPENAI_API_KEY", api: "openai-completions" },
430
+ dashscope: { baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1", apiKey: "DASHSCOPE_API_KEY", api: "openai-completions" },
431
+ openai: { baseUrl: "https://api.openai.com/v1", apiKey: "OPENAI_API_KEY", api: "openai-completions" },
432
+ /** 自定义端点,baseUrl 由用户填写,兼容所有 OpenAI 接口 */
433
+ "openai-custom": { baseUrl: "", apiKey: "OPENAI_API_KEY", api: "openai-completions" },
434
+ nvidia: { baseUrl: "https://integrate.api.nvidia.com/v1", apiKey: "NVIDIA_API_KEY", api: "openai-completions" },
435
+ kimi: { baseUrl: "https://api.moonshot.cn/v1", apiKey: "MOONSHOT_API_KEY", api: "openai-completions" },
436
+ };
437
+ const DEFAULT_COST = { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 };
438
+ const DEFAULT_CONTEXT_WINDOW = 64000;
439
+ const DEFAULT_MAX_TOKENS = 8192;
440
+ function configuredModelToPi(item, displayName) {
441
+ const cost = item.cost ?? {};
442
+ return {
443
+ id: item.modelId,
444
+ name: displayName,
445
+ reasoning: item.reasoning ?? false,
446
+ input: ["text"],
447
+ cost: {
448
+ input: cost.input ?? 0,
449
+ output: cost.output ?? 0,
450
+ cacheRead: cost.cacheRead ?? 0,
451
+ cacheWrite: cost.cacheWrite ?? 0,
452
+ },
453
+ contextWindow: item.contextWindow ?? DEFAULT_CONTEXT_WINDOW,
454
+ maxTokens: item.maxTokens ?? DEFAULT_MAX_TOKENS,
455
+ supportsTools: true,
456
+ };
457
+ }
458
+ /**
459
+ * 根据桌面 config(已配置的 providers + configuredModels)与 provider-support,生成并写入 agent 目录的 models.json。
460
+ * 仅包含在 config 的 providers 中已配置的 provider;每个 provider 的 models 来自 configuredModels,结构含 reasoning、cost 等。
461
+ */
462
+ export async function syncDesktopConfigToModelsJson() {
463
+ const config = await readDesktopConfigJson();
464
+ const configured = config.providers ?? {};
465
+ const configuredModels = Array.isArray(config.configuredModels) ? config.configuredModels : [];
466
+ if (Object.keys(configured).length === 0) {
467
+ return;
468
+ }
469
+ const support = await getProviderSupport();
470
+ const piProviders = {};
471
+ for (const [providerId, userConfig] of Object.entries(configured)) {
472
+ if (!userConfig?.apiKey?.trim())
473
+ continue;
474
+ const defaults = SYNC_DEFAULTS[providerId] ?? { baseUrl: "", apiKey: "OPENAI_API_KEY", api: "openai-completions" };
475
+ const baseUrl = userConfig.baseUrl?.trim() || (support[providerId]?.baseUrl ?? "").trim() || defaults.baseUrl;
476
+ if (!baseUrl)
477
+ continue;
478
+ const def = support[providerId];
479
+ const items = configuredModels.filter((m) => m.provider === providerId);
480
+ let models;
481
+ if (items.length > 0) {
482
+ models = items.map((item) => {
483
+ const displayName = (item.alias && item.alias.trim()) ||
484
+ (def?.models?.find((m) => m.id === item.modelId)?.name) ||
485
+ item.modelId;
486
+ return configuredModelToPi(item, displayName);
487
+ });
488
+ }
489
+ else if (def?.models?.length) {
490
+ models = def.models.map((m) => configuredModelToPi({
491
+ provider: providerId,
492
+ modelId: m.id,
493
+ type: "llm",
494
+ alias: m.name,
495
+ reasoning: false,
496
+ cost: DEFAULT_COST,
497
+ contextWindow: DEFAULT_CONTEXT_WINDOW,
498
+ maxTokens: DEFAULT_MAX_TOKENS,
499
+ }, m.name || m.id));
500
+ }
501
+ else {
502
+ continue;
503
+ }
504
+ piProviders[providerId] = {
505
+ name: (userConfig.alias?.trim() || def?.name) || providerId,
506
+ apiKey: defaults.apiKey,
507
+ api: defaults.api,
508
+ baseUrl: baseUrl.replace(/\/$/, ""),
509
+ authHeader: true,
510
+ models,
511
+ };
512
+ }
513
+ if (Object.keys(piProviders).length === 0)
514
+ return;
515
+ const agentDir = getOpenbotAgentDir();
516
+ if (!existsSync(agentDir)) {
517
+ mkdirSync(agentDir, { recursive: true });
518
+ }
519
+ const modelsPath = join(agentDir, "models.json");
520
+ await writeFile(modelsPath, JSON.stringify({ providers: piProviders }, null, 2), "utf-8");
521
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * 默认的 provider 及模型目录,供配置时下拉备选。
3
+ * 桌面 provider-support.json 若不存在则使用此默认并写入桌面目录。
4
+ * 官方 provider 可预设 baseUrl,CLI login 时会写入 config;未知或自定义 OpenAI 接口可不设。
5
+ */
6
+ /** 模型支持的能力类型,配置处(如 agent 配置、长记忆 embedding 选择)可按类型筛选可用模型 */
7
+ export type ModelSupportType = "llm" | "embedding" | "image" | "audio" | "video";
8
+ export interface ProviderSupportModel {
9
+ id: string;
10
+ name: string;
11
+ /** 支持的类型,如 llm / embedding / image / audio / video;缺省视为 ["llm"] */
12
+ types?: ModelSupportType[];
13
+ }
14
+ export interface ProviderSupportEntry {
15
+ name: string;
16
+ /** 官方 API 的 baseUrl,CLI login 时会写入 config;不设或空表示需用户在桌面填写(如自定义端点) */
17
+ baseUrl?: string;
18
+ models: ProviderSupportModel[];
19
+ }
20
+ export type ProviderSupport = Record<string, ProviderSupportEntry>;
21
+ export declare const DEFAULT_PROVIDER_SUPPORT: ProviderSupport;
@@ -0,0 +1,57 @@
1
+ export const DEFAULT_PROVIDER_SUPPORT = {
2
+ deepseek: {
3
+ name: "DeepSeek",
4
+ baseUrl: "https://api.deepseek.com",
5
+ models: [
6
+ { id: "deepseek-chat", name: "DeepSeek Chat", types: ["llm"] },
7
+ { id: "deepseek-reasoner", name: "DeepSeek Reasoner", types: ["llm"] },
8
+ ],
9
+ },
10
+ dashscope: {
11
+ name: "DashScope (Alibaba)",
12
+ baseUrl: "https://dashscope.aliyuncs.com/compatible-mode/v1",
13
+ models: [
14
+ { id: "qwen-max", name: "Qwen Max", types: ["llm"] },
15
+ { id: "qwen-plus", name: "Qwen Plus", types: ["llm"] },
16
+ ],
17
+ },
18
+ openai: {
19
+ name: "OpenAI",
20
+ baseUrl: "https://api.openai.com/v1",
21
+ models: [
22
+ { id: "gpt-4o", name: "GPT-4o", types: ["llm"] },
23
+ { id: "gpt-4o-mini", name: "GPT-4o Mini", types: ["llm"] },
24
+ { id: "text-embedding-3-small", name: "Text Embedding 3 Small", types: ["embedding"] },
25
+ ],
26
+ },
27
+ /** 自定义 Base URL,兼容所有 OpenAI 接口(本地/第三方兼容端点);baseUrl 不预设,由用户在桌面填写 */
28
+ "openai-custom": {
29
+ name: "OpenAI (自定义)",
30
+ models: [
31
+ { id: "gpt-4o", name: "GPT-4o", types: ["llm"] },
32
+ { id: "gpt-4o-mini", name: "GPT-4o Mini", types: ["llm"] },
33
+ { id: "gpt-4-turbo", name: "GPT-4 Turbo", types: ["llm"] },
34
+ { id: "gpt-3.5-turbo", name: "GPT-3.5 Turbo", types: ["llm"] },
35
+ { id: "text-embedding-3-small", name: "Text Embedding 3 Small", types: ["embedding"] },
36
+ { id: "text-embedding-ada-002", name: "Text Embedding Ada 002", types: ["embedding"] },
37
+ ],
38
+ },
39
+ nvidia: {
40
+ name: "NVIDIA",
41
+ baseUrl: "https://integrate.api.nvidia.com/v1",
42
+ models: [
43
+ { id: "moonshotai/kimi-k2.5", name: "Kimi K2.5", types: ["llm"] },
44
+ { id: "nvidia/nemotron-nano-12b-v2", name: "Nemotron Nano 12B v2", types: ["llm"] },
45
+ { id: "nvidia/nemotron-nano-9b-v2", name: "Nemotron Nano 9B v2", types: ["llm"] },
46
+ ],
47
+ },
48
+ kimi: {
49
+ name: "Kimi (Moonshot)",
50
+ baseUrl: "https://api.moonshot.cn/v1",
51
+ models: [
52
+ { id: "moonshot-v1-8k", name: "Moonshot 8K", types: ["llm"] },
53
+ { id: "moonshot-v1-32k", name: "Moonshot 32K", types: ["llm"] },
54
+ { id: "moonshot-v1-128k", name: "Moonshot 128K", types: ["llm"] },
55
+ ],
56
+ },
57
+ };
@@ -0,0 +1 @@
1
+ export { resolveInstallTarget, installSkillByUrl, installSkillFromPath, installSkillFromUpload, type InstallByUrlOptions, type InstallByUrlResult, type InstallFromPathOptions, type InstallFromPathResult, type InstallFromUploadOptions, } from "./skill-installer.js";
@@ -0,0 +1 @@
1
+ export { resolveInstallTarget, installSkillByUrl, installSkillFromPath, installSkillFromUpload, } from "./skill-installer.js";
@@ -0,0 +1,39 @@
1
+ /** 解析 targetAgentId 得到安装目标:global 或 workspace + 工作区名 */
2
+ export declare function resolveInstallTarget(targetAgentId: string | undefined): Promise<{
3
+ scope: "global" | "workspace";
4
+ workspace: string;
5
+ }>;
6
+ export interface InstallByUrlOptions {
7
+ scope: "global" | "workspace";
8
+ workspace?: string;
9
+ }
10
+ export interface InstallByUrlResult {
11
+ stdout: string;
12
+ stderr: string;
13
+ installDir: string;
14
+ }
15
+ /**
16
+ * 通过 npx skills add 安装技能到指定目录(与 Nest SkillsService 逻辑一致)。
17
+ */
18
+ export declare function installSkillByUrl(url: string, options?: InstallByUrlOptions): Promise<InstallByUrlResult>;
19
+ export interface InstallFromPathOptions {
20
+ scope: "global" | "workspace";
21
+ workspace?: string;
22
+ }
23
+ export interface InstallFromPathResult {
24
+ installDir: string;
25
+ name: string;
26
+ }
27
+ /**
28
+ * 从本地目录安装技能:将指定目录复制到目标 skills 目录。
29
+ */
30
+ export declare function installSkillFromPath(localPath: string, options?: InstallFromPathOptions): Promise<InstallFromPathResult>;
31
+ export interface InstallFromUploadOptions {
32
+ scope: "global" | "workspace";
33
+ workspace?: string;
34
+ }
35
+ /**
36
+ * 从上传的 zip 安装技能:解压到临时目录,校验为单个技能目录(含 SKILL.md),再复制到目标。
37
+ * 支持两种 zip 结构:① 单个顶层目录且内含 SKILL.md;② 根目录直接含 SKILL.md(将视为技能根目录)。
38
+ */
39
+ export declare function installSkillFromUpload(zipBuffer: Buffer, options?: InstallFromUploadOptions): Promise<InstallFromPathResult>;