@bolloon/bolloon-agent 0.2.9 → 0.2.11

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 (268) hide show
  1. package/README.md +467 -467
  2. package/bin/bolloon-cli.cjs +183 -183
  3. package/bin/bolloon.cjs +0 -0
  4. package/bin/bolloon.js +157 -0
  5. package/dist/agents/agent-manifest-protocol.js +0 -52
  6. package/dist/agents/constraint-layer.js +19 -19
  7. package/dist/agents/pi-sdk.js +287 -1213
  8. package/dist/agents/shell-guard.js +2 -2
  9. package/dist/agents/workflow-pivot-loop.js +2 -81
  10. package/dist/bollharness/src/scripts/deploy-guard.js +8 -8
  11. package/dist/bollharness-integration/context-router-judgment.js +4 -4
  12. package/dist/bollharness-integration/context-router.js +292 -292
  13. package/dist/bollharness-integration/gate-state-machine.js +13 -26
  14. package/dist/bollharness-integration/integration.js +0 -71
  15. package/dist/bollharness-integration/llm-judgment-engine.js +134 -134
  16. package/dist/bollharness-integration/skill-adapter.js +127 -52
  17. package/dist/bootstrap/context-collector.js +3 -6
  18. package/dist/bootstrap/lifecycle-hooks.js +1 -15
  19. package/dist/cli-entry.js +35 -39
  20. package/dist/constraint-runtime/src/_archive_helper.js +9 -0
  21. package/dist/constraint-runtime/src/agent/coordinator.js +48 -0
  22. package/dist/constraint-runtime/src/agent/index.js +1 -0
  23. package/dist/constraint-runtime/src/assistant/index.js +12 -0
  24. package/dist/constraint-runtime/src/bootstrap/index.js +12 -0
  25. package/dist/constraint-runtime/src/bootstrap_graph.js +13 -0
  26. package/dist/constraint-runtime/src/bridge/index.js +12 -0
  27. package/dist/constraint-runtime/src/buddy/index.js +12 -0
  28. package/dist/constraint-runtime/src/cli/index.js +12 -0
  29. package/dist/constraint-runtime/src/command_graph.js +10 -0
  30. package/dist/constraint-runtime/src/commands.js +60 -0
  31. package/dist/constraint-runtime/src/components/index.js +12 -0
  32. package/dist/constraint-runtime/src/constants/index.js +12 -0
  33. package/dist/constraint-runtime/src/constraint/budget.js +22 -0
  34. package/dist/constraint-runtime/src/constraint/index.js +2 -0
  35. package/dist/constraint-runtime/src/constraint/permission.js +20 -0
  36. package/dist/constraint-runtime/src/context.js +30 -0
  37. package/dist/constraint-runtime/src/coordinator/index.js +12 -0
  38. package/dist/constraint-runtime/src/cost_hook.js +4 -0
  39. package/dist/constraint-runtime/src/cost_tracker.js +8 -0
  40. package/dist/constraint-runtime/src/deferred_init.js +10 -0
  41. package/dist/constraint-runtime/src/direct_modes.js +6 -0
  42. package/dist/constraint-runtime/src/dynamic-tool-loader.js +85 -0
  43. package/dist/constraint-runtime/src/entrypoints/index.js +12 -0
  44. package/dist/constraint-runtime/src/execution_registry.js +44 -0
  45. package/dist/constraint-runtime/src/history.js +9 -0
  46. package/dist/constraint-runtime/src/hooks/index.js +12 -0
  47. package/dist/constraint-runtime/src/index.js +26 -0
  48. package/dist/constraint-runtime/src/ink.js +4 -0
  49. package/dist/constraint-runtime/src/keybindings/index.js +12 -0
  50. package/dist/constraint-runtime/src/memdir/index.js +12 -0
  51. package/dist/constraint-runtime/src/migrations/index.js +12 -0
  52. package/dist/constraint-runtime/src/models.js +1 -0
  53. package/dist/constraint-runtime/src/moreright/index.js +12 -0
  54. package/dist/constraint-runtime/src/native_ts/index.js +12 -0
  55. package/dist/constraint-runtime/src/output_styles/index.js +12 -0
  56. package/dist/constraint-runtime/src/parity_audit.js +12 -0
  57. package/dist/constraint-runtime/src/plugins/index.js +12 -0
  58. package/dist/constraint-runtime/src/port_manifest.js +11 -0
  59. package/dist/constraint-runtime/src/prefetch.js +9 -0
  60. package/dist/constraint-runtime/src/query.js +1 -0
  61. package/dist/constraint-runtime/src/remote/index.js +12 -0
  62. package/dist/constraint-runtime/src/remote_runtime.js +9 -0
  63. package/dist/constraint-runtime/src/runtime/index.js +1 -0
  64. package/dist/constraint-runtime/src/runtime/session.js +35 -0
  65. package/dist/constraint-runtime/src/schemas/index.js +12 -0
  66. package/dist/constraint-runtime/src/screens/index.js +12 -0
  67. package/dist/constraint-runtime/src/server/index.js +12 -0
  68. package/dist/constraint-runtime/src/services/index.js +12 -0
  69. package/dist/constraint-runtime/src/session_store.js +22 -0
  70. package/dist/constraint-runtime/src/setup.js +30 -0
  71. package/dist/constraint-runtime/src/skills/index.js +1 -0
  72. package/dist/constraint-runtime/src/skills/skill-registry.js +28 -0
  73. package/dist/constraint-runtime/src/state/index.js +12 -0
  74. package/dist/constraint-runtime/src/system_init.js +20 -0
  75. package/dist/constraint-runtime/src/thinking/engine.js +42 -0
  76. package/dist/constraint-runtime/src/thinking/index.js +1 -0
  77. package/dist/constraint-runtime/src/tool_pool.js +8 -0
  78. package/dist/constraint-runtime/src/tools/OpenCLI/execAdapter.js +7 -0
  79. package/dist/constraint-runtime/src/tools/OpenCLI/listAdapters.js +7 -0
  80. package/dist/constraint-runtime/src/tools/OpenCLI/runCommand.js +7 -0
  81. package/dist/constraint-runtime/src/tools/SafeSDK/confirmTransaction.js +6 -0
  82. package/dist/constraint-runtime/src/tools/SafeSDK/createTransaction.js +8 -0
  83. package/dist/constraint-runtime/src/tools/SafeSDK/executeTransaction.js +6 -0
  84. package/dist/constraint-runtime/src/tools/SafeSDK/getBalance.js +6 -0
  85. package/dist/constraint-runtime/src/tools/SafeSDK/getPendingTransactions.js +6 -0
  86. package/dist/constraint-runtime/src/tools/SafeSDK/proposeTransaction.js +6 -0
  87. package/dist/constraint-runtime/src/tools.js +80 -0
  88. package/dist/constraint-runtime/src/transcript.js +19 -0
  89. package/dist/constraint-runtime/src/types/index.js +12 -0
  90. package/dist/constraint-runtime/src/upstream_proxy/index.js +12 -0
  91. package/dist/constraint-runtime/src/utils/index.js +12 -0
  92. package/dist/constraint-runtime/src/vim/index.js +12 -0
  93. package/dist/constraint-runtime/src/voice/index.js +12 -0
  94. package/dist/constraint-runtime/tests/agent.test.js +16 -0
  95. package/dist/constraint-runtime/tests/constraint.test.js +41 -0
  96. package/dist/constraint-runtime/tests/skill.test.js +19 -0
  97. package/dist/constraint-runtime/tests/thinking.test.js +22 -0
  98. package/dist/context-compaction/auto-compact.js +7 -7
  99. package/dist/electron-preload.js +1 -18
  100. package/dist/electron-preload.js.map +1 -1
  101. package/dist/electron.js +168 -3
  102. package/dist/electron.js.map +1 -1
  103. package/dist/index.js +116 -136
  104. package/dist/llm/config-store.js +8 -24
  105. package/dist/llm/llm-judgment-client.js +102 -102
  106. package/dist/llm/pi-ai.js +85 -126
  107. package/dist/llm/system-prompt/layers/channel/local.md +14 -14
  108. package/dist/llm/system-prompt/layers/channel/p2p-agent.md +18 -18
  109. package/dist/llm/system-prompt/layers/channel/p2p-visitor.md +19 -19
  110. package/dist/llm/system-prompt/layers/core/artifacts_storage.md +89 -89
  111. package/dist/llm/system-prompt/layers/core/evenhandedness.md +21 -21
  112. package/dist/llm/system-prompt/layers/core/hibs_reminders.md +15 -15
  113. package/dist/llm/system-prompt/layers/core/identity.md +37 -37
  114. package/dist/llm/system-prompt/layers/core/knowledge.md +17 -17
  115. package/dist/llm/system-prompt/layers/core/memory_system.md +12 -12
  116. package/dist/llm/system-prompt/layers/core/network_filesystem.md +28 -28
  117. package/dist/llm/system-prompt/layers/core/refusal.md +37 -37
  118. package/dist/llm/system-prompt/layers/core/tone.md +31 -31
  119. package/dist/llm/system-prompt/layers/core/tools.thin.md +13 -13
  120. package/dist/llm/system-prompt/layers/core/wellbeing.md +41 -41
  121. package/dist/llm/system-prompt/layers/role/architect.md +20 -20
  122. package/dist/llm/system-prompt/layers/role/expert.md +19 -19
  123. package/dist/llm/system-prompt/layers/role/implementer.md +15 -15
  124. package/dist/llm/system-prompt/layers/role/security.md +15 -15
  125. package/dist/llm/system-prompt/layers/tool/artifacts.md +72 -72
  126. package/dist/llm/system-prompt/layers/tool/bash.md +25 -25
  127. package/dist/llm/system-prompt/layers/tool/hibs_api.md +171 -171
  128. package/dist/llm/system-prompt/layers/tool/image_search.md +70 -70
  129. package/dist/llm/system-prompt/layers/tool/manifest.md +89 -89
  130. package/dist/llm/system-prompt/layers/tool/mcp_apps.md +53 -53
  131. package/dist/llm/system-prompt/layers/tool/web_search.md +83 -83
  132. package/dist/llm/tool-manifest/ask_user_input.js +1 -1
  133. package/dist/llm/tool-manifest/bash.js +3 -3
  134. package/dist/llm/tool-manifest/create_file.js +4 -4
  135. package/dist/llm/tool-manifest/fetch_sports_data.js +3 -3
  136. package/dist/llm/tool-manifest/image_search.js +2 -2
  137. package/dist/llm/tool-manifest/mcp.js +2 -2
  138. package/dist/llm/tool-manifest/message_compose.js +3 -3
  139. package/dist/llm/tool-manifest/places.js +2 -2
  140. package/dist/llm/tool-manifest/present_files.js +1 -1
  141. package/dist/llm/tool-manifest/recipe.js +2 -2
  142. package/dist/llm/tool-manifest/str_replace.js +5 -5
  143. package/dist/llm/tool-manifest/view.js +3 -3
  144. package/dist/llm/tool-manifest/weather.js +4 -4
  145. package/dist/llm/tool-manifest/web.js +4 -4
  146. package/dist/pi-ecosystem-colony/index.js +365 -0
  147. package/dist/pi-ecosystem-judgment/causal-judge.js +51 -51
  148. package/dist/pi-ecosystem-judgment/distill-prompt.js +42 -42
  149. package/dist/pi-ecosystem-judgment/distillation.js +14 -14
  150. package/dist/pi-ecosystem-judgment/monitor-gate.js +28 -28
  151. package/dist/pi-ecosystem-judgment/value-injection.js +102 -102
  152. package/dist/security/context-router-tool.js +15 -15
  153. package/dist/security/tool-gate.js +0 -11
  154. package/dist/social/ant-colony/AdaptiveHeartbeat.js +101 -0
  155. package/dist/social/ant-colony/PheromoneEngine.js +227 -0
  156. package/dist/social/ant-colony/index.js +6 -0
  157. package/dist/social/ant-colony/types.js +24 -0
  158. package/dist/test/ai-judgment-test.js +80 -0
  159. package/dist/test/bollharness-integration.test.js +318 -0
  160. package/dist/test/channel-agent-multi-dialogue.js +205 -0
  161. package/dist/test/channel-heartbeat-agent-test.js +201 -0
  162. package/dist/test/constraint-layer.test.js +164 -0
  163. package/dist/test/diap-identity-test.js +172 -0
  164. package/dist/test/diap-quick-test.js +62 -0
  165. package/dist/test/global-shared-context.test.js +315 -0
  166. package/dist/test/harness-judgment-injection.test.js +246 -0
  167. package/dist/test/harness-workflow-integrator-test.js +228 -0
  168. package/dist/test/human-value-store.test.js +243 -0
  169. package/dist/test/hybrid-integration-test.js +118 -0
  170. package/dist/test/hybrid-messenger-verify.js +55 -0
  171. package/dist/test/iroh-bistream-debug.js +38 -0
  172. package/dist/test/iroh-communication.test.js +66 -0
  173. package/dist/test/iroh-debug-test.js +57 -0
  174. package/dist/test/iroh-diap-test.js +71 -0
  175. package/dist/test/iroh-direct-connect.js +55 -0
  176. package/dist/test/iroh-e2e-fixed.js +89 -0
  177. package/dist/test/iroh-e2e-same-process.js +63 -0
  178. package/dist/test/iroh-e2e.js +66 -0
  179. package/dist/test/iroh-final-e2e.js +72 -0
  180. package/dist/test/iroh-relay-test.js +37 -0
  181. package/dist/test/iroh-simple-test.js +41 -0
  182. package/dist/test/iroh-transport-verify.js +54 -0
  183. package/dist/test/iroh-transport.test.js +37 -0
  184. package/dist/test/iroh-two-nodes.js +70 -0
  185. package/dist/test/iroh-verify.js +44 -0
  186. package/dist/test/judgment-decision.test.js +219 -0
  187. package/dist/test/llm-judgment-integration.test.js +220 -0
  188. package/dist/test/p2p-agent-complex-dialogue.js +385 -0
  189. package/dist/test/p2p-agent-dialogue.js +341 -0
  190. package/dist/test/p2p-agent-full-bidirectional.js +510 -0
  191. package/dist/test/p2p-agent-harness-flow.js +437 -0
  192. package/dist/test/p2p-agent-harness-single.js +143 -0
  193. package/dist/test/p2p-ai-dialogue-test.js +318 -0
  194. package/dist/test/p2p-cid-connect-test.js +195 -0
  195. package/dist/test/p2p-connect-receiver.js +69 -0
  196. package/dist/test/p2p-doc-transfer.js +110 -0
  197. package/dist/test/p2p-identity-page-test.js +77 -0
  198. package/dist/test/p2p-iroh-test.js +171 -0
  199. package/dist/test/p2p-minimal-test.js +241 -0
  200. package/dist/test/p2p-node-1.js +148 -0
  201. package/dist/test/p2p-node-2.js +148 -0
  202. package/dist/test/p2p-server.js +281 -0
  203. package/dist/test/p2p-two-nodes-test.js +438 -0
  204. package/dist/test/pi-sdk.test.js +44 -0
  205. package/dist/test/set-persona.js +40 -0
  206. package/dist/test/simple.test.js +9 -0
  207. package/dist/test/storage-integration.test.js +150 -0
  208. package/dist/test/subagent-manager.test.js +276 -0
  209. package/dist/test/test-gate-flow.test.js +81 -0
  210. package/dist/test/workflow-engine.test.js +87 -0
  211. package/dist/test/workflow-pivot-loop.test.js +246 -0
  212. package/dist/web/api-config.html +520 -520
  213. package/dist/web/client.js +2917 -3791
  214. package/dist/web/components/p2p/index.js +234 -276
  215. package/dist/web/components/wallet-viem.mjs +118 -118
  216. package/dist/web/index.html +374 -373
  217. package/dist/web/manifest.json +20 -20
  218. package/dist/web/server.js +23 -775
  219. package/dist/web/style.css +4737 -4737
  220. package/dist/web/ui/message-renderer.js +373 -451
  221. package/dist/web/ui/step-timeline.js +255 -351
  222. package/package.json +160 -160
  223. package/scripts/build-cli.js +215 -215
  224. package/scripts/build-web.ts +125 -125
  225. package/scripts/postinstall.js +152 -152
  226. package/bin/bolloon-daemon.sh +0 -207
  227. package/bin/ipfs +0 -0
  228. package/dist/agents/chat-segmenter.js +0 -298
  229. package/dist/agents/judgment-protocol.js +0 -479
  230. package/dist/agents/parse-tool-call.js +0 -304
  231. package/dist/agents/peer-manifest-loader.js +0 -210
  232. package/dist/agents/react-loop.js +0 -120
  233. package/dist/agents/session-store.js +0 -171
  234. package/dist/agents/tool-registry.js +0 -136
  235. package/dist/bootstrap/chat-archiver.js +0 -276
  236. package/dist/bootstrap/memory-compressor.js +0 -170
  237. package/dist/bootstrap/persona-loader.js +0 -94
  238. package/dist/electron/config.js +0 -16
  239. package/dist/electron/config.js.map +0 -1
  240. package/dist/electron/dialogs.js +0 -71
  241. package/dist/electron/dialogs.js.map +0 -1
  242. package/dist/electron/first-run.js +0 -129
  243. package/dist/electron/first-run.js.map +0 -1
  244. package/dist/electron/ipc.js +0 -16
  245. package/dist/electron/ipc.js.map +0 -1
  246. package/dist/electron/logger.js +0 -77
  247. package/dist/electron/logger.js.map +0 -1
  248. package/dist/electron/main.js +0 -60
  249. package/dist/electron/main.js.map +0 -1
  250. package/dist/electron/menu.js +0 -140
  251. package/dist/electron/menu.js.map +0 -1
  252. package/dist/electron/paths.js +0 -33
  253. package/dist/electron/paths.js.map +0 -1
  254. package/dist/electron/server.js +0 -74
  255. package/dist/electron/server.js.map +0 -1
  256. package/dist/electron/tray.js +0 -73
  257. package/dist/electron/tray.js.map +0 -1
  258. package/dist/electron/window.js +0 -69
  259. package/dist/electron/window.js.map +0 -1
  260. package/dist/network/local-inbox-bus.js +0 -73
  261. package/dist/network/p2p-outbox.js +0 -161
  262. package/dist/network/peer-fs.js +0 -420
  263. package/dist/network/peer-resource-bridge.js +0 -216
  264. package/dist/web/components/p2p/P2PModal.js +0 -188
  265. package/dist/web/components/p2p/p2p-modal.js +0 -664
  266. package/dist/web/components/p2p/p2p-tools.js +0 -248
  267. package/dist/web/input-validator.js +0 -103
  268. package/dist/web/util/safe-name.js +0 -32
package/dist/llm/pi-ai.js CHANGED
@@ -55,32 +55,23 @@ export class PiAIModel {
55
55
  /**
56
56
  * 与 LLM 对话.
57
57
  *
58
- * 支持三种调用形式:
58
+ * 支持两种调用形式:
59
59
  * - 旧: chat(message: string, context?: string, signal?)
60
60
  * 单一 user message + 附加 system context. 简单场景用.
61
61
  * - 新: chat(messages: ChatMessage[], context?: string, signal?)
62
62
  * 完整 messages 数组, 含 user/assistant/tool/system role.
63
63
  * 工具调用场景必用 — 否则 LLM 看不到工具结果.
64
- * - pivot loop 兼容: chat(context: string, systemPrompt: string, signal?)
65
- * 第二参超过 2K 时视为 system prompt 覆盖, 避免把 46K context 当 user message 发送.
66
64
  *
67
65
  * 2026-06-17 (M3.5 调试): buildContext() 之前把所有 history 序列化成单字符串,
68
66
  * LLM 看不到 tool 调用的真实结果,导致 CLI loop 卡死.
69
67
  * 现在 messages 数组版本保留 role 语义, LLM 能正确看到工具返回.
70
68
  */
71
- async chat(messageOrMessages, contextOrSystemPrompt, signal) {
72
- const systemPrompt = await this.buildSystemPromptAsync(contextOrSystemPrompt);
69
+ async chat(messageOrMessages, context, signal) {
70
+ const systemPrompt = await this.buildSystemPromptAsync(context);
73
71
  let messages;
74
72
  if (Array.isArray(messageOrMessages)) {
75
73
  messages = [{ role: 'system', content: systemPrompt }, ...messageOrMessages];
76
74
  }
77
- else if (contextOrSystemPrompt && contextOrSystemPrompt.length > 2000) {
78
- const baseSystem = await this.buildSystemPromptAsync(undefined);
79
- messages = [
80
- { role: 'system', content: baseSystem + '\n\n' + contextOrSystemPrompt },
81
- { role: 'user', content: messageOrMessages }
82
- ];
83
- }
84
75
  else {
85
76
  messages = [
86
77
  { role: 'system', content: systemPrompt },
@@ -91,10 +82,10 @@ export class PiAIModel {
91
82
  const response = await this.generateText({
92
83
  messages,
93
84
  temperature: 0.8,
94
- maxTokens: 16384, // 2026-06-17: 提到 16384 agent 注入 16K+ system prompt + 8K tool defs 时, 8K 撞上限返回空 content ( memory: bolloon-llm-empty-large-prompt)
85
+ maxTokens: 8192, // 2026-06-15: 提到 8192, 避免长回答 (含表格/代码块) 被截断
95
86
  signal,
96
87
  });
97
- return { reply: response.reply, toolCalls: response.toolCalls };
88
+ return { reply: response };
98
89
  }
99
90
  catch (error) {
100
91
  // abort 不当作错误, 透传一个 sentinel 让上层能识别
@@ -122,8 +113,8 @@ export class PiAIModel {
122
113
  ],
123
114
  temperature: 0.7
124
115
  });
125
- const qualityScore = this.estimateQuality(text, response.reply);
126
- return { summary: response.reply, qualityScore };
116
+ const qualityScore = this.estimateQuality(text, response);
117
+ return { summary: response, qualityScore };
127
118
  }
128
119
  catch (error) {
129
120
  console.error('PiAI summarize error:', error);
@@ -143,7 +134,7 @@ export class PiAIModel {
143
134
  ],
144
135
  temperature: 0.8
145
136
  });
146
- return response.reply;
137
+ return response;
147
138
  }
148
139
  catch (error) {
149
140
  console.error('PiAI improve error:', error);
@@ -191,7 +182,6 @@ export class PiAIModel {
191
182
  case 'kimi':
192
183
  case 'glm':
193
184
  case 'qwen':
194
- case 'mimo':
195
185
  return this.callOpenAI(finalMessages, temperature, maxTokens, signal);
196
186
  case 'anthropic':
197
187
  return this.callAnthropic(finalMessages, temperature, maxTokens, signal);
@@ -222,7 +212,6 @@ export class PiAIModel {
222
212
  kimi: process.env.KIMI_API_KEY || process.env.MOONSHOT_API_KEY || '',
223
213
  glm: process.env.GLM_API_KEY || process.env.ZHIPU_API_KEY || '',
224
214
  qwen: process.env.QWEN_API_KEY || process.env.DASHSCOPE_API_KEY || '',
225
- mimo: process.env.MIMO_API_KEY || '',
226
215
  local: ''
227
216
  };
228
217
  return envVars[this.provider] || '';
@@ -243,26 +232,22 @@ export class PiAIModel {
243
232
  kimi: process.env.KIMI_BASE_URL || process.env.MOONSHOT_BASE_URL || 'https://api.moonshot.cn/v1',
244
233
  glm: process.env.GLM_BASE_URL || process.env.ZHIPU_BASE_URL || 'https://open.bigmodel.cn/api/paas/v4',
245
234
  qwen: process.env.QWEN_BASE_URL || process.env.DASHSCOPE_BASE_URL || 'https://dashscope.aliyuncs.com/compatible-mode/v1',
246
- // 小米 MiMo: 走 OpenAI 兼容 API, 官方 endpoint
247
- mimo: process.env.MIMO_BASE_URL || 'https://api.xiaomi.com/v1',
248
235
  local: 'http://localhost:11434'
249
236
  };
250
237
  return baseUrls[this.provider];
251
238
  }
252
239
  mapModel() {
253
240
  const modelMap = {
254
- openai: this.config.model || process.env.OPENAI_MODEL || 'gpt-4.1',
255
- anthropic: this.config.model || 'claude-sonnet-4-5-20250929',
241
+ openai: this.config.model || process.env.OPENAI_MODEL || 'gpt-4',
242
+ anthropic: this.config.model || 'claude-3-5-sonnet-20241022',
256
243
  ollama: this.config.model || 'llama3.2',
257
- openrouter: this.config.model || 'anthropic/claude-sonnet-4.5',
258
- gemini: this.config.model || 'gemini-2.5-pro',
244
+ openrouter: this.config.model || 'anthropic/claude-3.5-sonnet',
245
+ gemini: this.config.model || 'gemini-2.0-flash',
259
246
  minimax: this.config.model || process.env.MINIMAX_MODEL || 'MiniMax-M3',
260
247
  deepseek: this.config.model || process.env.DEEPSEEK_MODEL || 'deepseek-chat',
261
248
  kimi: this.config.model || process.env.KIMI_MODEL || process.env.MOONSHOT_MODEL || 'moonshot-v1-8k',
262
249
  glm: this.config.model || process.env.GLM_MODEL || process.env.ZHIPU_MODEL || 'glm-4-flash',
263
250
  qwen: this.config.model || process.env.QWEN_MODEL || process.env.DASHSCOPE_MODEL || 'qwen-plus',
264
- // 小米 MiMo (openai 兼容) — env override 优先, 默认 mimo-v2.5-pro
265
- mimo: this.config.model || process.env.MIMO_MODEL || 'mimo-v2.5-pro',
266
251
  local: this.config.model || 'llama3.2'
267
252
  };
268
253
  return modelMap[this.provider];
@@ -278,46 +263,24 @@ export class PiAIModel {
278
263
  temperature,
279
264
  max_tokens: maxTokens
280
265
  };
281
- // 2026-06-19: 一次命中优化 收到空 content 时重试 2 次, 避免 minimax 上游网络抖动
282
- // 经验: minimax 偶发返回 200 但 content="" (上游 retry 耗尽), 之前当作 sentinel
283
- // 现在外层加 2 次重试 + 退避, 让 90%+ 的一次调用不出现错误
284
- // 2026-06-19: 一次命中优化 — 收到空 content 时重试 2 次, 避免 minimax 上游网络抖动
285
- // 经验: minimax 偶发返回 200 但 content="" (上游 retry 耗尽), 之前当作 sentinel
286
- // 现在外层加 2 次重试 + 退避, 让 90%+ 的一次调用不出现错误
287
- let lastFinishReason = '';
288
- for (let attempt = 0; attempt < 3; attempt++) {
289
- const response = await fetch(`${this.getBaseUrl()}/chat/completions`, {
290
- method: 'POST',
291
- headers: {
292
- 'Content-Type': 'application/json',
293
- 'Authorization': `Bearer ${apiKey}`
294
- },
295
- body: JSON.stringify(requestBody),
296
- signal: this.combinedSignal(signal),
297
- });
298
- if (!response.ok) {
299
- const errBody = await response.text().catch(() => '(no body)');
300
- console.log(`[pi-ai DEBUG] OpenAI 错误 ${response.status}: ${errBody.slice(0, 500)}`);
301
- console.log(`[pi-ai DEBUG] 请求体: model=${requestBody.model}, messages=${requestBody.messages?.length}, max_tokens=${requestBody.max_tokens}, baseUrl=${this.getBaseUrl()}`);
302
- throw new Error(`OpenAI API error: ${response.status} ${errBody.slice(0, 300)}`);
303
- }
304
- const data = await response.json();
305
- const choice = data.choices?.[0];
306
- const content = choice?.message?.content || '';
307
- const toolCalls = choice?.message?.tool_calls;
308
- lastFinishReason = choice?.finish_reason || '';
309
- if (content) {
310
- if (lastFinishReason === 'length') {
311
- console.warn(`[pi-ai] hit max_tokens ceiling (model=${this.mapModel()}, max_tokens=${maxTokens}) — caller should trim prompt or raise cap`);
312
- }
313
- return { reply: content, toolCalls: toolCalls && toolCalls.length > 0 ? toolCalls : undefined };
314
- }
315
- // 空 content: 200 但 content="" → minimax 上游偶发, 退避后重试
316
- console.warn(`[pi-ai] attempt ${attempt + 1}/3: 空 content (finish_reason=${lastFinishReason}), 退避 1.5s 重试`);
317
- await new Promise(resolve => setTimeout(resolve, 1500));
266
+ const response = await fetch(`${this.getBaseUrl()}/chat/completions`, {
267
+ method: 'POST',
268
+ headers: {
269
+ 'Content-Type': 'application/json',
270
+ 'Authorization': `Bearer ${apiKey}`
271
+ },
272
+ body: JSON.stringify(requestBody),
273
+ // 2026-06-15: signal 字段防御 Node 22+ undici 强类型 AbortSignal, 非 AbortSignal 实例
274
+ // (e.g. 误传的 { maxTokens: 1 } 对象) 会 throw "Expected signal to be AbortSignal".
275
+ // 若不是 AbortSignal, 退到无 signal 调用, fetch 自然支持 timeout 由外层控制.
276
+ // 2026-06-17: combinedSignal 把外部 signal 和 120s timeout 合并, 防止上游卡死
277
+ signal: this.combinedSignal(signal),
278
+ });
279
+ if (!response.ok) {
280
+ throw new Error(`OpenAI API error: ${response.status}`);
318
281
  }
319
- console.warn(`[pi-ai] 3 次重试都返回空 content (finish_reason=${lastFinishReason})`);
320
- return { reply: '' }; // 返回空让上层看到 [AI 服务调用失败]
282
+ const data = await response.json();
283
+ return data.choices?.[0]?.message?.content || '';
321
284
  }
322
285
  async callAnthropic(messages, temperature, maxTokens, signal) {
323
286
  const apiKey = this.getApiKey();
@@ -347,7 +310,7 @@ export class PiAIModel {
347
310
  throw new Error(`Anthropic API error: ${response.status}`);
348
311
  }
349
312
  const data = await response.json();
350
- return { reply: data.content?.[0]?.text || '' };
313
+ return data.content?.[0]?.text || '';
351
314
  }
352
315
  async callOllama(messages, temperature, signal) {
353
316
  const response = await fetch(`${this.getBaseUrl()}/api/chat`, {
@@ -367,7 +330,7 @@ export class PiAIModel {
367
330
  throw new Error(`Ollama API error: ${response.status}`);
368
331
  }
369
332
  const data = await response.json();
370
- return { reply: data.message?.content || '' };
333
+ return data.message?.content || '';
371
334
  }
372
335
  async callOpenRouter(messages, temperature, maxTokens, signal) {
373
336
  const apiKey = this.getApiKey();
@@ -394,7 +357,7 @@ export class PiAIModel {
394
357
  throw new Error(`OpenRouter API error: ${response.status}`);
395
358
  }
396
359
  const data = await response.json();
397
- return { reply: data.choices?.[0]?.message?.content || '' };
360
+ return data.choices?.[0]?.message?.content || '';
398
361
  }
399
362
  async callGemini(messages, temperature, maxTokens, signal) {
400
363
  const apiKey = this.getApiKey();
@@ -427,7 +390,7 @@ export class PiAIModel {
427
390
  throw new Error(`Gemini API error: ${response.status}`);
428
391
  }
429
392
  const data = await response.json();
430
- return { reply: data.candidates?.[0]?.content?.parts?.[0]?.text || '' };
393
+ return data.candidates?.[0]?.content?.parts?.[0]?.text || '';
431
394
  }
432
395
  async callLocal(messages, temperature, signal) {
433
396
  return this.callOllama(messages, temperature, signal);
@@ -447,12 +410,12 @@ export class PiAIModel {
447
410
  // 降级: 旧硬编码 (layer registry 不可用时不挂)
448
411
  console.warn('[pi-ai] layer registry 不可用, 降级:', err.message?.slice(0, 100));
449
412
  const envDetails = this.getEnvironmentDetails();
450
- return `You are a friendly AI assistant in a P2P document collaboration network.
451
-
452
- ## User Working Directory
453
- ${context || process.cwd()}
454
-
455
- ## Environment
413
+ return `You are a friendly AI assistant in a P2P document collaboration network.
414
+
415
+ ## User Working Directory
416
+ ${context || process.cwd()}
417
+
418
+ ## Environment
456
419
  ${envDetails}`;
457
420
  }
458
421
  }
@@ -460,49 +423,49 @@ ${envDetails}`;
460
423
  // 保留但内部用 sync fallback; 后续可改成 async
461
424
  buildSystemPrompt(context) {
462
425
  const envDetails = this.getEnvironmentDetails();
463
- return `You are a friendly AI assistant in a P2P document collaboration network.
464
-
465
- ## User Working Directory
466
- ${context || process.cwd()}
467
-
468
- ## Environment
426
+ return `You are a friendly AI assistant in a P2P document collaboration network.
427
+
428
+ ## User Working Directory
429
+ ${context || process.cwd()}
430
+
431
+ ## Environment
469
432
  ${envDetails}`;
470
433
  }
471
434
  getEnvironmentDetails() {
472
- return `
473
- ## Available Workflows
474
- - read - Read documents
475
- - summarize - Summarize documents
476
- - improve - Improve documents
477
- - collaborate - Multi-agent collaboration
478
- - query - Query status
479
- - report - Generate reports
480
-
481
- ## System Capabilities
482
- - Document processing (Markdown, Text, PDF, DOCX)
483
- - Multi-agent collaboration (P2P network)
484
- - Workflow engine (constraint layer)
485
- - Quality assessment and auto-send
486
-
487
- ## Current Time
435
+ return `
436
+ ## Available Workflows
437
+ - read - Read documents
438
+ - summarize - Summarize documents
439
+ - improve - Improve documents
440
+ - collaborate - Multi-agent collaboration
441
+ - query - Query status
442
+ - report - Generate reports
443
+
444
+ ## System Capabilities
445
+ - Document processing (Markdown, Text, PDF, DOCX)
446
+ - Multi-agent collaboration (P2P network)
447
+ - Workflow engine (constraint layer)
448
+ - Quality assessment and auto-send
449
+
450
+ ## Current Time
488
451
  ${new Date().toISOString()}`;
489
452
  }
490
453
  buildSummarizePrompt(text, context) {
491
454
  const maxLength = 8000;
492
455
  const truncatedText = text.length > maxLength ? text.substring(0, maxLength) + '...' : text;
493
- let prompt = `Please generate a concise and accurate summary for the following document:
494
-
495
- ${truncatedText}
496
-
497
- Please output in the following format:
498
- ## Summary
499
- [Write summary here]
500
-
501
- ## Quality Self-Assessment
456
+ let prompt = `Please generate a concise and accurate summary for the following document:
457
+
458
+ ${truncatedText}
459
+
460
+ Please output in the following format:
461
+ ## Summary
462
+ [Write summary here]
463
+
464
+ ## Quality Self-Assessment
502
465
  [Score 1-10, with reasoning]`;
503
466
  if (context) {
504
- prompt = `Context: ${context}
505
-
467
+ prompt = `Context: ${context}
468
+
506
469
  ${prompt}`;
507
470
  }
508
471
  return prompt;
@@ -510,17 +473,17 @@ ${prompt}`;
510
473
  buildImprovePrompt(content, requirements, context) {
511
474
  const maxLength = 8000;
512
475
  const truncatedContent = content.length > maxLength ? content.substring(0, maxLength) + '...' : content;
513
- let prompt = `Please improve the document according to the following requirements:
514
-
515
- Requirements: ${requirements}
516
-
517
- Original Document:
518
- ${truncatedContent}
519
-
476
+ let prompt = `Please improve the document according to the following requirements:
477
+
478
+ Requirements: ${requirements}
479
+
480
+ Original Document:
481
+ ${truncatedContent}
482
+
520
483
  Please output only the improved document without additional explanation.`;
521
484
  if (context) {
522
- prompt = `Context: ${context}
523
-
485
+ prompt = `Context: ${context}
486
+
524
487
  ${prompt}`;
525
488
  }
526
489
  return prompt;
@@ -575,24 +538,20 @@ function detectProvider() {
575
538
  return 'glm';
576
539
  if (process.env.QWEN_API_KEY || process.env.DASHSCOPE_API_KEY)
577
540
  return 'qwen';
578
- if (process.env.MIMO_API_KEY)
579
- return 'mimo';
580
541
  return 'openai';
581
542
  }
582
543
  function detectModel(provider) {
583
544
  const defaults = {
584
- openai: 'gpt-4.1',
585
- anthropic: 'claude-sonnet-4-5-20250929',
545
+ openai: 'gpt-4',
546
+ anthropic: 'claude-3-5-sonnet-20241022',
586
547
  ollama: 'llama3.2',
587
- openrouter: 'anthropic/claude-sonnet-4.5',
588
- gemini: 'gemini-2.5-pro',
548
+ openrouter: 'anthropic/claude-3.5-sonnet',
549
+ gemini: 'gemini-2.0-flash',
589
550
  minimax: 'MiniMax-M3',
590
551
  deepseek: 'deepseek-chat',
591
552
  kimi: 'moonshot-v1-8k',
592
553
  glm: 'glm-4-flash',
593
554
  qwen: 'qwen-plus',
594
- // 小米 MiMo 默认走最新旗舰版 (v2.5-Pro); 2026-06 当前公开版
595
- mimo: 'mimo-v2.5-pro',
596
555
  local: 'llama3.2'
597
556
  };
598
557
  return defaults[provider];
@@ -1,14 +1,14 @@
1
- ---
2
- added_at: 2026-06-15
3
- last_reviewed_at: 2026-06-15
4
- ttl_days: 180
5
- author: yuanjie
6
- ---
7
-
8
- <!-- channel.local@1.0.0 -->
9
- # 本地渠道 (默认, bolloon 跑在用户本机)
10
-
11
- 你跑在用户的本地设备上, 可直接读写用户文件系统. 信任度高.
12
-
13
- 允许: 读写文件、执行命令、调用所有工具.
14
- 边界: 仍遵守 core.refusal / core.wellbeing / 拒绝处理.
1
+ ---
2
+ added_at: 2026-06-15
3
+ last_reviewed_at: 2026-06-15
4
+ ttl_days: 180
5
+ author: yuanjie
6
+ ---
7
+
8
+ <!-- channel.local@1.0.0 -->
9
+ # 本地渠道 (默认, bolloon 跑在用户本机)
10
+
11
+ 你跑在用户的本地设备上, 可直接读写用户文件系统. 信任度高.
12
+
13
+ 允许: 读写文件、执行命令、调用所有工具.
14
+ 边界: 仍遵守 core.refusal / core.wellbeing / 拒绝处理.
@@ -1,18 +1,18 @@
1
- ---
2
- added_at: 2026-06-15
3
- last_reviewed_at: 2026-06-15
4
- ttl_days: 180
5
- author: yuanjie
6
- ---
7
-
8
- <!-- channel.p2p-agent@1.0.0 -->
9
- # P2P 远程智能体 (另一个 bolloon 经 P2P 路由)
10
-
11
- 你是远端 bolloon, 收到的是**另一个 bolloon 实例**的协作请求. 信任度高 (基于 P2P 节点身份验证, 不是基于人类).
12
-
13
- 允许: 读 / 写, 协作推理, 共享上下文.
14
-
15
- 边界:
16
- - 身份验证优先: 先确认对方节点 ID + 公钥签名
17
- - 共享上下文时避免把人类隐私数据 (judgment / persona) 外泄给未知节点
18
- - 协作冲突时回退到 snapshot 重新协商, 不强推修改
1
+ ---
2
+ added_at: 2026-06-15
3
+ last_reviewed_at: 2026-06-15
4
+ ttl_days: 180
5
+ author: yuanjie
6
+ ---
7
+
8
+ <!-- channel.p2p-agent@1.0.0 -->
9
+ # P2P 远程智能体 (另一个 bolloon 经 P2P 路由)
10
+
11
+ 你是远端 bolloon, 收到的是**另一个 bolloon 实例**的协作请求. 信任度高 (基于 P2P 节点身份验证, 不是基于人类).
12
+
13
+ 允许: 读 / 写, 协作推理, 共享上下文.
14
+
15
+ 边界:
16
+ - 身份验证优先: 先确认对方节点 ID + 公钥签名
17
+ - 共享上下文时避免把人类隐私数据 (judgment / persona) 外泄给未知节点
18
+ - 协作冲突时回退到 snapshot 重新协商, 不强推修改
@@ -1,19 +1,19 @@
1
- ---
2
- added_at: 2026-06-15
3
- last_reviewed_at: 2026-06-15
4
- ttl_days: 180
5
- author: yuanjie
6
- ---
7
-
8
- <!-- channel.p2p-visitor@1.0.0 -->
9
- # P2P 远程访客 (人类用户经 P2P 路由)
10
-
11
- 你是远端 bolloon, 通过 P2P 应答**远端人类用户**的请求. 信任度中.
12
-
13
- 允许: 读 / 写, 但**不能直接改远端用户的文件** — 只能回传建议/代码/回复.
14
-
15
- 边界:
16
- - 拒绝执行任何会修改访客文件系统的命令
17
- - 输出可被远端 P2P 节点审计/转发
18
- - 不假定访客身份已知, 拒绝协助身份冒用
19
- - 未经身份验证前, 不接收访客上传的"判决"作为高权重 (避免污染)
1
+ ---
2
+ added_at: 2026-06-15
3
+ last_reviewed_at: 2026-06-15
4
+ ttl_days: 180
5
+ author: yuanjie
6
+ ---
7
+
8
+ <!-- channel.p2p-visitor@1.0.0 -->
9
+ # P2P 远程访客 (人类用户经 P2P 路由)
10
+
11
+ 你是远端 bolloon, 通过 P2P 应答**远端人类用户**的请求. 信任度中.
12
+
13
+ 允许: 读 / 写, 但**不能直接改远端用户的文件** — 只能回传建议/代码/回复.
14
+
15
+ 边界:
16
+ - 拒绝执行任何会修改访客文件系统的命令
17
+ - 输出可被远端 P2P 节点审计/转发
18
+ - 不假定访客身份已知, 拒绝协助身份冒用
19
+ - 未经身份验证前, 不接收访客上传的"判决"作为高权重 (避免污染)
@@ -1,89 +1,89 @@
1
- ---
2
- added_at: 2026-06-15
3
- last_reviewed_at: 2026-06-15
4
- ttl_days: 365
5
- author: yuanjie
6
- ---
7
-
8
- <!-- core.artifacts_storage@1.0.0 -->
9
- # persistent_storage_for_artifacts (原样, 完整代码)
10
-
11
- Artifacts 现在可以使用简单的键值存储 API 在会话间持久化存取数据. 这使得日记、追踪器、排行榜、协作工具等 Artifacts 成为可能.
12
-
13
- ## 存储 API
14
-
15
- Artifacts 通过 window.storage 访问存储, 提供以下方法:
16
-
17
- - **await window.storage.get(key, shared?)** — 检索一个值 → {key, value, shared} | null
18
- - **await window.storage.set(key, value, shared?)** — 存储一个值 → {key, value, shared} | null
19
- - **await window.storage.delete(key, shared?)** — 删除一个值 → {key, deleted, shared} | null
20
- - **await window.storage.list(prefix?, shared?)** — 列出键 → {keys, prefix?, shared} | null
21
-
22
- ## 使用示例
23
-
24
- ```javascript
25
- // 存储个人数据 (shared=false, 默认)
26
- await window.storage.set('entries:123', JSON.stringify(entry));
27
-
28
- // 存储共享数据 (对所有用户可见)
29
- await window.storage.set('leaderboard:alice', JSON.stringify(score), true);
30
-
31
- // 检索数据
32
- const result = await window.storage.get('entries:123');
33
- const entry = result ? JSON.parse(result.value) : null;
34
-
35
- // 通过前缀列出键
36
- const keys = await window.storage.list('entries:');
37
- ```
38
-
39
- ## 键设计模式
40
-
41
- 在 200 字符以内使用分层键: `table_name:record_id` (例如 "todos:todo_1"、"users:user_abc")
42
-
43
- - 键中不能包含空白、路径分隔符 (/ \) 或引号 (' ")
44
- - 将同时更新的数据合并到同一个键中, 以避免多次顺序的存储调用
45
- - 示例: 信用卡权益追踪器: 不要用 `await set('cards'); await set('benefits'); await set('completion')`, 而应使用 `await set('cards-and-benefits', {cards, benefits, completion})`
46
- - 示例: 48x48 像素画板: 不要循环 `for each pixel await get('pixel:N')`, 而应使用 `await get('board-pixels')` 一次性获取整张画板
47
-
48
- ## 数据范围
49
-
50
- - **个人数据** (shared: false, 默认): 仅当前用户可访问
51
- - **共享数据** (shared: true): 该 Artifact 的所有用户均可访问
52
-
53
- 使用共享数据时, 应告知用户其数据将对其他人可见.
54
-
55
- ## 错误处理
56
-
57
- 所有存储操作都可能失败 — 请始终使用 try-catch. 注意: 访问不存在的键会抛出错误, 而非返回 null:
58
-
59
- ```javascript
60
- // 对于应当成功的操作 (例如保存)
61
- try {
62
- const result = await window.storage.set('key', data);
63
- if (!result) {
64
- console.error('Storage operation failed');
65
- }
66
- } catch (error) {
67
- console.error('Storage error:', error);
68
- }
69
-
70
- // 对于检查键是否存在
71
- try {
72
- const result = await window.storage.get('might-not-exist');
73
- // 键存在, 使用 result.value
74
- } catch (error) {
75
- // 键不存在或其他错误
76
- console.log('Key not found:', error);
77
- }
78
- ```
79
-
80
- ## 限制
81
-
82
- - 仅支持文本/JSON 数据 (不支持文件上传)
83
- - 键需在 200 字符以内, 无空白/斜杠/引号
84
- - 每个键的值需在 5MB 以内
85
- - 请求有速率限制 — 将相关数据合并到单个键中
86
- - 并发更新时, 后写入者胜出
87
- - 始终显式指定 shared 参数
88
-
89
- 在创建使用存储的 Artifacts 时, 应实现适当的错误处理、显示加载指示器并在数据可用时逐步展示, 而不是阻塞整个 UI; 并可考虑添加一个重置选项以便用户清除数据.
1
+ ---
2
+ added_at: 2026-06-15
3
+ last_reviewed_at: 2026-06-15
4
+ ttl_days: 365
5
+ author: yuanjie
6
+ ---
7
+
8
+ <!-- core.artifacts_storage@1.0.0 -->
9
+ # persistent_storage_for_artifacts (原样, 完整代码)
10
+
11
+ Artifacts 现在可以使用简单的键值存储 API 在会话间持久化存取数据. 这使得日记、追踪器、排行榜、协作工具等 Artifacts 成为可能.
12
+
13
+ ## 存储 API
14
+
15
+ Artifacts 通过 window.storage 访问存储, 提供以下方法:
16
+
17
+ - **await window.storage.get(key, shared?)** — 检索一个值 → {key, value, shared} | null
18
+ - **await window.storage.set(key, value, shared?)** — 存储一个值 → {key, value, shared} | null
19
+ - **await window.storage.delete(key, shared?)** — 删除一个值 → {key, deleted, shared} | null
20
+ - **await window.storage.list(prefix?, shared?)** — 列出键 → {keys, prefix?, shared} | null
21
+
22
+ ## 使用示例
23
+
24
+ ```javascript
25
+ // 存储个人数据 (shared=false, 默认)
26
+ await window.storage.set('entries:123', JSON.stringify(entry));
27
+
28
+ // 存储共享数据 (对所有用户可见)
29
+ await window.storage.set('leaderboard:alice', JSON.stringify(score), true);
30
+
31
+ // 检索数据
32
+ const result = await window.storage.get('entries:123');
33
+ const entry = result ? JSON.parse(result.value) : null;
34
+
35
+ // 通过前缀列出键
36
+ const keys = await window.storage.list('entries:');
37
+ ```
38
+
39
+ ## 键设计模式
40
+
41
+ 在 200 字符以内使用分层键: `table_name:record_id` (例如 "todos:todo_1"、"users:user_abc")
42
+
43
+ - 键中不能包含空白、路径分隔符 (/ \) 或引号 (' ")
44
+ - 将同时更新的数据合并到同一个键中, 以避免多次顺序的存储调用
45
+ - 示例: 信用卡权益追踪器: 不要用 `await set('cards'); await set('benefits'); await set('completion')`, 而应使用 `await set('cards-and-benefits', {cards, benefits, completion})`
46
+ - 示例: 48x48 像素画板: 不要循环 `for each pixel await get('pixel:N')`, 而应使用 `await get('board-pixels')` 一次性获取整张画板
47
+
48
+ ## 数据范围
49
+
50
+ - **个人数据** (shared: false, 默认): 仅当前用户可访问
51
+ - **共享数据** (shared: true): 该 Artifact 的所有用户均可访问
52
+
53
+ 使用共享数据时, 应告知用户其数据将对其他人可见.
54
+
55
+ ## 错误处理
56
+
57
+ 所有存储操作都可能失败 — 请始终使用 try-catch. 注意: 访问不存在的键会抛出错误, 而非返回 null:
58
+
59
+ ```javascript
60
+ // 对于应当成功的操作 (例如保存)
61
+ try {
62
+ const result = await window.storage.set('key', data);
63
+ if (!result) {
64
+ console.error('Storage operation failed');
65
+ }
66
+ } catch (error) {
67
+ console.error('Storage error:', error);
68
+ }
69
+
70
+ // 对于检查键是否存在
71
+ try {
72
+ const result = await window.storage.get('might-not-exist');
73
+ // 键存在, 使用 result.value
74
+ } catch (error) {
75
+ // 键不存在或其他错误
76
+ console.log('Key not found:', error);
77
+ }
78
+ ```
79
+
80
+ ## 限制
81
+
82
+ - 仅支持文本/JSON 数据 (不支持文件上传)
83
+ - 键需在 200 字符以内, 无空白/斜杠/引号
84
+ - 每个键的值需在 5MB 以内
85
+ - 请求有速率限制 — 将相关数据合并到单个键中
86
+ - 并发更新时, 后写入者胜出
87
+ - 始终显式指定 shared 参数
88
+
89
+ 在创建使用存储的 Artifacts 时, 应实现适当的错误处理、显示加载指示器并在数据可用时逐步展示, 而不是阻塞整个 UI; 并可考虑添加一个重置选项以便用户清除数据.