@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.
- package/README.md +467 -467
- package/bin/bolloon-cli.cjs +183 -183
- package/bin/bolloon.cjs +0 -0
- package/bin/bolloon.js +157 -0
- package/dist/agents/agent-manifest-protocol.js +0 -52
- package/dist/agents/constraint-layer.js +19 -19
- package/dist/agents/pi-sdk.js +287 -1213
- package/dist/agents/shell-guard.js +2 -2
- package/dist/agents/workflow-pivot-loop.js +2 -81
- package/dist/bollharness/src/scripts/deploy-guard.js +8 -8
- package/dist/bollharness-integration/context-router-judgment.js +4 -4
- package/dist/bollharness-integration/context-router.js +292 -292
- package/dist/bollharness-integration/gate-state-machine.js +13 -26
- package/dist/bollharness-integration/integration.js +0 -71
- package/dist/bollharness-integration/llm-judgment-engine.js +134 -134
- package/dist/bollharness-integration/skill-adapter.js +127 -52
- package/dist/bootstrap/context-collector.js +3 -6
- package/dist/bootstrap/lifecycle-hooks.js +1 -15
- package/dist/cli-entry.js +35 -39
- package/dist/constraint-runtime/src/_archive_helper.js +9 -0
- package/dist/constraint-runtime/src/agent/coordinator.js +48 -0
- package/dist/constraint-runtime/src/agent/index.js +1 -0
- package/dist/constraint-runtime/src/assistant/index.js +12 -0
- package/dist/constraint-runtime/src/bootstrap/index.js +12 -0
- package/dist/constraint-runtime/src/bootstrap_graph.js +13 -0
- package/dist/constraint-runtime/src/bridge/index.js +12 -0
- package/dist/constraint-runtime/src/buddy/index.js +12 -0
- package/dist/constraint-runtime/src/cli/index.js +12 -0
- package/dist/constraint-runtime/src/command_graph.js +10 -0
- package/dist/constraint-runtime/src/commands.js +60 -0
- package/dist/constraint-runtime/src/components/index.js +12 -0
- package/dist/constraint-runtime/src/constants/index.js +12 -0
- package/dist/constraint-runtime/src/constraint/budget.js +22 -0
- package/dist/constraint-runtime/src/constraint/index.js +2 -0
- package/dist/constraint-runtime/src/constraint/permission.js +20 -0
- package/dist/constraint-runtime/src/context.js +30 -0
- package/dist/constraint-runtime/src/coordinator/index.js +12 -0
- package/dist/constraint-runtime/src/cost_hook.js +4 -0
- package/dist/constraint-runtime/src/cost_tracker.js +8 -0
- package/dist/constraint-runtime/src/deferred_init.js +10 -0
- package/dist/constraint-runtime/src/direct_modes.js +6 -0
- package/dist/constraint-runtime/src/dynamic-tool-loader.js +85 -0
- package/dist/constraint-runtime/src/entrypoints/index.js +12 -0
- package/dist/constraint-runtime/src/execution_registry.js +44 -0
- package/dist/constraint-runtime/src/history.js +9 -0
- package/dist/constraint-runtime/src/hooks/index.js +12 -0
- package/dist/constraint-runtime/src/index.js +26 -0
- package/dist/constraint-runtime/src/ink.js +4 -0
- package/dist/constraint-runtime/src/keybindings/index.js +12 -0
- package/dist/constraint-runtime/src/memdir/index.js +12 -0
- package/dist/constraint-runtime/src/migrations/index.js +12 -0
- package/dist/constraint-runtime/src/models.js +1 -0
- package/dist/constraint-runtime/src/moreright/index.js +12 -0
- package/dist/constraint-runtime/src/native_ts/index.js +12 -0
- package/dist/constraint-runtime/src/output_styles/index.js +12 -0
- package/dist/constraint-runtime/src/parity_audit.js +12 -0
- package/dist/constraint-runtime/src/plugins/index.js +12 -0
- package/dist/constraint-runtime/src/port_manifest.js +11 -0
- package/dist/constraint-runtime/src/prefetch.js +9 -0
- package/dist/constraint-runtime/src/query.js +1 -0
- package/dist/constraint-runtime/src/remote/index.js +12 -0
- package/dist/constraint-runtime/src/remote_runtime.js +9 -0
- package/dist/constraint-runtime/src/runtime/index.js +1 -0
- package/dist/constraint-runtime/src/runtime/session.js +35 -0
- package/dist/constraint-runtime/src/schemas/index.js +12 -0
- package/dist/constraint-runtime/src/screens/index.js +12 -0
- package/dist/constraint-runtime/src/server/index.js +12 -0
- package/dist/constraint-runtime/src/services/index.js +12 -0
- package/dist/constraint-runtime/src/session_store.js +22 -0
- package/dist/constraint-runtime/src/setup.js +30 -0
- package/dist/constraint-runtime/src/skills/index.js +1 -0
- package/dist/constraint-runtime/src/skills/skill-registry.js +28 -0
- package/dist/constraint-runtime/src/state/index.js +12 -0
- package/dist/constraint-runtime/src/system_init.js +20 -0
- package/dist/constraint-runtime/src/thinking/engine.js +42 -0
- package/dist/constraint-runtime/src/thinking/index.js +1 -0
- package/dist/constraint-runtime/src/tool_pool.js +8 -0
- package/dist/constraint-runtime/src/tools/OpenCLI/execAdapter.js +7 -0
- package/dist/constraint-runtime/src/tools/OpenCLI/listAdapters.js +7 -0
- package/dist/constraint-runtime/src/tools/OpenCLI/runCommand.js +7 -0
- package/dist/constraint-runtime/src/tools/SafeSDK/confirmTransaction.js +6 -0
- package/dist/constraint-runtime/src/tools/SafeSDK/createTransaction.js +8 -0
- package/dist/constraint-runtime/src/tools/SafeSDK/executeTransaction.js +6 -0
- package/dist/constraint-runtime/src/tools/SafeSDK/getBalance.js +6 -0
- package/dist/constraint-runtime/src/tools/SafeSDK/getPendingTransactions.js +6 -0
- package/dist/constraint-runtime/src/tools/SafeSDK/proposeTransaction.js +6 -0
- package/dist/constraint-runtime/src/tools.js +80 -0
- package/dist/constraint-runtime/src/transcript.js +19 -0
- package/dist/constraint-runtime/src/types/index.js +12 -0
- package/dist/constraint-runtime/src/upstream_proxy/index.js +12 -0
- package/dist/constraint-runtime/src/utils/index.js +12 -0
- package/dist/constraint-runtime/src/vim/index.js +12 -0
- package/dist/constraint-runtime/src/voice/index.js +12 -0
- package/dist/constraint-runtime/tests/agent.test.js +16 -0
- package/dist/constraint-runtime/tests/constraint.test.js +41 -0
- package/dist/constraint-runtime/tests/skill.test.js +19 -0
- package/dist/constraint-runtime/tests/thinking.test.js +22 -0
- package/dist/context-compaction/auto-compact.js +7 -7
- package/dist/electron-preload.js +1 -18
- package/dist/electron-preload.js.map +1 -1
- package/dist/electron.js +168 -3
- package/dist/electron.js.map +1 -1
- package/dist/index.js +116 -136
- package/dist/llm/config-store.js +8 -24
- package/dist/llm/llm-judgment-client.js +102 -102
- package/dist/llm/pi-ai.js +85 -126
- package/dist/llm/system-prompt/layers/channel/local.md +14 -14
- package/dist/llm/system-prompt/layers/channel/p2p-agent.md +18 -18
- package/dist/llm/system-prompt/layers/channel/p2p-visitor.md +19 -19
- package/dist/llm/system-prompt/layers/core/artifacts_storage.md +89 -89
- package/dist/llm/system-prompt/layers/core/evenhandedness.md +21 -21
- package/dist/llm/system-prompt/layers/core/hibs_reminders.md +15 -15
- package/dist/llm/system-prompt/layers/core/identity.md +37 -37
- package/dist/llm/system-prompt/layers/core/knowledge.md +17 -17
- package/dist/llm/system-prompt/layers/core/memory_system.md +12 -12
- package/dist/llm/system-prompt/layers/core/network_filesystem.md +28 -28
- package/dist/llm/system-prompt/layers/core/refusal.md +37 -37
- package/dist/llm/system-prompt/layers/core/tone.md +31 -31
- package/dist/llm/system-prompt/layers/core/tools.thin.md +13 -13
- package/dist/llm/system-prompt/layers/core/wellbeing.md +41 -41
- package/dist/llm/system-prompt/layers/role/architect.md +20 -20
- package/dist/llm/system-prompt/layers/role/expert.md +19 -19
- package/dist/llm/system-prompt/layers/role/implementer.md +15 -15
- package/dist/llm/system-prompt/layers/role/security.md +15 -15
- package/dist/llm/system-prompt/layers/tool/artifacts.md +72 -72
- package/dist/llm/system-prompt/layers/tool/bash.md +25 -25
- package/dist/llm/system-prompt/layers/tool/hibs_api.md +171 -171
- package/dist/llm/system-prompt/layers/tool/image_search.md +70 -70
- package/dist/llm/system-prompt/layers/tool/manifest.md +89 -89
- package/dist/llm/system-prompt/layers/tool/mcp_apps.md +53 -53
- package/dist/llm/system-prompt/layers/tool/web_search.md +83 -83
- package/dist/llm/tool-manifest/ask_user_input.js +1 -1
- package/dist/llm/tool-manifest/bash.js +3 -3
- package/dist/llm/tool-manifest/create_file.js +4 -4
- package/dist/llm/tool-manifest/fetch_sports_data.js +3 -3
- package/dist/llm/tool-manifest/image_search.js +2 -2
- package/dist/llm/tool-manifest/mcp.js +2 -2
- package/dist/llm/tool-manifest/message_compose.js +3 -3
- package/dist/llm/tool-manifest/places.js +2 -2
- package/dist/llm/tool-manifest/present_files.js +1 -1
- package/dist/llm/tool-manifest/recipe.js +2 -2
- package/dist/llm/tool-manifest/str_replace.js +5 -5
- package/dist/llm/tool-manifest/view.js +3 -3
- package/dist/llm/tool-manifest/weather.js +4 -4
- package/dist/llm/tool-manifest/web.js +4 -4
- package/dist/pi-ecosystem-colony/index.js +365 -0
- package/dist/pi-ecosystem-judgment/causal-judge.js +51 -51
- package/dist/pi-ecosystem-judgment/distill-prompt.js +42 -42
- package/dist/pi-ecosystem-judgment/distillation.js +14 -14
- package/dist/pi-ecosystem-judgment/monitor-gate.js +28 -28
- package/dist/pi-ecosystem-judgment/value-injection.js +102 -102
- package/dist/security/context-router-tool.js +15 -15
- package/dist/security/tool-gate.js +0 -11
- package/dist/social/ant-colony/AdaptiveHeartbeat.js +101 -0
- package/dist/social/ant-colony/PheromoneEngine.js +227 -0
- package/dist/social/ant-colony/index.js +6 -0
- package/dist/social/ant-colony/types.js +24 -0
- package/dist/test/ai-judgment-test.js +80 -0
- package/dist/test/bollharness-integration.test.js +318 -0
- package/dist/test/channel-agent-multi-dialogue.js +205 -0
- package/dist/test/channel-heartbeat-agent-test.js +201 -0
- package/dist/test/constraint-layer.test.js +164 -0
- package/dist/test/diap-identity-test.js +172 -0
- package/dist/test/diap-quick-test.js +62 -0
- package/dist/test/global-shared-context.test.js +315 -0
- package/dist/test/harness-judgment-injection.test.js +246 -0
- package/dist/test/harness-workflow-integrator-test.js +228 -0
- package/dist/test/human-value-store.test.js +243 -0
- package/dist/test/hybrid-integration-test.js +118 -0
- package/dist/test/hybrid-messenger-verify.js +55 -0
- package/dist/test/iroh-bistream-debug.js +38 -0
- package/dist/test/iroh-communication.test.js +66 -0
- package/dist/test/iroh-debug-test.js +57 -0
- package/dist/test/iroh-diap-test.js +71 -0
- package/dist/test/iroh-direct-connect.js +55 -0
- package/dist/test/iroh-e2e-fixed.js +89 -0
- package/dist/test/iroh-e2e-same-process.js +63 -0
- package/dist/test/iroh-e2e.js +66 -0
- package/dist/test/iroh-final-e2e.js +72 -0
- package/dist/test/iroh-relay-test.js +37 -0
- package/dist/test/iroh-simple-test.js +41 -0
- package/dist/test/iroh-transport-verify.js +54 -0
- package/dist/test/iroh-transport.test.js +37 -0
- package/dist/test/iroh-two-nodes.js +70 -0
- package/dist/test/iroh-verify.js +44 -0
- package/dist/test/judgment-decision.test.js +219 -0
- package/dist/test/llm-judgment-integration.test.js +220 -0
- package/dist/test/p2p-agent-complex-dialogue.js +385 -0
- package/dist/test/p2p-agent-dialogue.js +341 -0
- package/dist/test/p2p-agent-full-bidirectional.js +510 -0
- package/dist/test/p2p-agent-harness-flow.js +437 -0
- package/dist/test/p2p-agent-harness-single.js +143 -0
- package/dist/test/p2p-ai-dialogue-test.js +318 -0
- package/dist/test/p2p-cid-connect-test.js +195 -0
- package/dist/test/p2p-connect-receiver.js +69 -0
- package/dist/test/p2p-doc-transfer.js +110 -0
- package/dist/test/p2p-identity-page-test.js +77 -0
- package/dist/test/p2p-iroh-test.js +171 -0
- package/dist/test/p2p-minimal-test.js +241 -0
- package/dist/test/p2p-node-1.js +148 -0
- package/dist/test/p2p-node-2.js +148 -0
- package/dist/test/p2p-server.js +281 -0
- package/dist/test/p2p-two-nodes-test.js +438 -0
- package/dist/test/pi-sdk.test.js +44 -0
- package/dist/test/set-persona.js +40 -0
- package/dist/test/simple.test.js +9 -0
- package/dist/test/storage-integration.test.js +150 -0
- package/dist/test/subagent-manager.test.js +276 -0
- package/dist/test/test-gate-flow.test.js +81 -0
- package/dist/test/workflow-engine.test.js +87 -0
- package/dist/test/workflow-pivot-loop.test.js +246 -0
- package/dist/web/api-config.html +520 -520
- package/dist/web/client.js +2917 -3791
- package/dist/web/components/p2p/index.js +234 -276
- package/dist/web/components/wallet-viem.mjs +118 -118
- package/dist/web/index.html +374 -373
- package/dist/web/manifest.json +20 -20
- package/dist/web/server.js +23 -775
- package/dist/web/style.css +4737 -4737
- package/dist/web/ui/message-renderer.js +373 -451
- package/dist/web/ui/step-timeline.js +255 -351
- package/package.json +160 -160
- package/scripts/build-cli.js +215 -215
- package/scripts/build-web.ts +125 -125
- package/scripts/postinstall.js +152 -152
- package/bin/bolloon-daemon.sh +0 -207
- package/bin/ipfs +0 -0
- package/dist/agents/chat-segmenter.js +0 -298
- package/dist/agents/judgment-protocol.js +0 -479
- package/dist/agents/parse-tool-call.js +0 -304
- package/dist/agents/peer-manifest-loader.js +0 -210
- package/dist/agents/react-loop.js +0 -120
- package/dist/agents/session-store.js +0 -171
- package/dist/agents/tool-registry.js +0 -136
- package/dist/bootstrap/chat-archiver.js +0 -276
- package/dist/bootstrap/memory-compressor.js +0 -170
- package/dist/bootstrap/persona-loader.js +0 -94
- package/dist/electron/config.js +0 -16
- package/dist/electron/config.js.map +0 -1
- package/dist/electron/dialogs.js +0 -71
- package/dist/electron/dialogs.js.map +0 -1
- package/dist/electron/first-run.js +0 -129
- package/dist/electron/first-run.js.map +0 -1
- package/dist/electron/ipc.js +0 -16
- package/dist/electron/ipc.js.map +0 -1
- package/dist/electron/logger.js +0 -77
- package/dist/electron/logger.js.map +0 -1
- package/dist/electron/main.js +0 -60
- package/dist/electron/main.js.map +0 -1
- package/dist/electron/menu.js +0 -140
- package/dist/electron/menu.js.map +0 -1
- package/dist/electron/paths.js +0 -33
- package/dist/electron/paths.js.map +0 -1
- package/dist/electron/server.js +0 -74
- package/dist/electron/server.js.map +0 -1
- package/dist/electron/tray.js +0 -73
- package/dist/electron/tray.js.map +0 -1
- package/dist/electron/window.js +0 -69
- package/dist/electron/window.js.map +0 -1
- package/dist/network/local-inbox-bus.js +0 -73
- package/dist/network/p2p-outbox.js +0 -161
- package/dist/network/peer-fs.js +0 -420
- package/dist/network/peer-resource-bridge.js +0 -216
- package/dist/web/components/p2p/P2PModal.js +0 -188
- package/dist/web/components/p2p/p2p-modal.js +0 -664
- package/dist/web/components/p2p/p2p-tools.js +0 -248
- package/dist/web/input-validator.js +0 -103
- 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,
|
|
72
|
-
const systemPrompt = await this.buildSystemPromptAsync(
|
|
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:
|
|
85
|
+
maxTokens: 8192, // 2026-06-15: 提到 8192, 避免长回答 (含表格/代码块) 被截断
|
|
95
86
|
signal,
|
|
96
87
|
});
|
|
97
|
-
return { reply: response
|
|
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
|
|
126
|
-
return { summary: response
|
|
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
|
|
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
|
|
255
|
-
anthropic: this.config.model || 'claude-
|
|
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-
|
|
258
|
-
gemini: this.config.model || 'gemini-2.
|
|
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
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
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
|
-
|
|
320
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
585
|
-
anthropic: 'claude-
|
|
545
|
+
openai: 'gpt-4',
|
|
546
|
+
anthropic: 'claude-3-5-sonnet-20241022',
|
|
586
547
|
ollama: 'llama3.2',
|
|
587
|
-
openrouter: 'anthropic/claude-
|
|
588
|
-
gemini: 'gemini-2.
|
|
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; 并可考虑添加一个重置选项以便用户清除数据.
|