@bolloon/bolloon-agent 0.2.11 → 0.2.13

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 (284) hide show
  1. package/README.md +495 -467
  2. package/bin/bolloon-cli.cjs +183 -183
  3. package/bin/bolloon-daemon.sh +207 -0
  4. package/bin/bolloon.cjs +0 -0
  5. package/bin/ipfs +0 -0
  6. package/dist/agents/agent-manifest-protocol.js +52 -0
  7. package/dist/agents/chat-segmenter.js +298 -0
  8. package/dist/agents/constraint-layer.js +19 -19
  9. package/dist/agents/judgment-protocol.js +479 -0
  10. package/dist/agents/parse-tool-call.js +304 -0
  11. package/dist/agents/peer-manifest-loader.js +210 -0
  12. package/dist/agents/pi-sdk-session-factory.js +110 -0
  13. package/dist/agents/pi-sdk-session-manager.js +297 -0
  14. package/dist/agents/pi-sdk-tools.js +1288 -0
  15. package/dist/agents/pi-sdk-types.js +13 -0
  16. package/dist/agents/pi-sdk.js +553 -1306
  17. package/dist/agents/react-loop.js +120 -0
  18. package/dist/agents/session-store.js +171 -0
  19. package/dist/agents/shell-guard.js +2 -2
  20. package/dist/agents/tool-registry.js +136 -0
  21. package/dist/agents/workflow-pivot-loop.js +200 -22
  22. package/dist/bollharness/src/scripts/context_router.js +7 -0
  23. package/dist/bollharness/src/scripts/deploy-guard.js +8 -8
  24. package/dist/bollharness-integration/context-router-judgment.js +4 -4
  25. package/dist/bollharness-integration/context-router.js +292 -292
  26. package/dist/bollharness-integration/gate-state-machine.js +26 -13
  27. package/dist/bollharness-integration/integration.js +71 -0
  28. package/dist/bollharness-integration/llm-judgment-engine.js +134 -134
  29. package/dist/bollharness-integration/skill-adapter.js +57 -127
  30. package/dist/bootstrap/chat-archiver.js +276 -0
  31. package/dist/bootstrap/context-collector.js +6 -3
  32. package/dist/bootstrap/event-log.js +160 -0
  33. package/dist/bootstrap/lifecycle-hooks.js +15 -1
  34. package/dist/bootstrap/memory-compressor.js +170 -0
  35. package/dist/bootstrap/persona-loader.js +94 -0
  36. package/dist/bootstrap/project-state.js +159 -0
  37. package/dist/bootstrap/remote-mirror.js +97 -0
  38. package/dist/bootstrap/session-window.js +121 -0
  39. package/dist/bootstrap/vector-index.js +248 -0
  40. package/dist/cli/loading-tui.js +40 -0
  41. package/dist/cli-entry.js +41 -37
  42. package/dist/context-compaction/auto-compact.js +7 -7
  43. package/dist/electron/config.js +21 -0
  44. package/dist/electron/config.js.map +1 -0
  45. package/dist/electron/dialogs.js +108 -0
  46. package/dist/electron/dialogs.js.map +1 -0
  47. package/dist/electron/first-run.js +170 -0
  48. package/dist/electron/first-run.js.map +1 -0
  49. package/dist/electron/ipc.js +20 -0
  50. package/dist/electron/ipc.js.map +1 -0
  51. package/dist/electron/logger.js +114 -0
  52. package/dist/electron/logger.js.map +1 -0
  53. package/dist/electron/main.js +63 -0
  54. package/dist/electron/main.js.map +1 -0
  55. package/dist/electron/menu.js +145 -0
  56. package/dist/electron/menu.js.map +1 -0
  57. package/dist/electron/paths.js +75 -0
  58. package/dist/electron/paths.js.map +1 -0
  59. package/dist/electron/server.js +119 -0
  60. package/dist/electron/server.js.map +1 -0
  61. package/dist/electron/tray.js +111 -0
  62. package/dist/electron/tray.js.map +1 -0
  63. package/dist/electron/window.js +111 -0
  64. package/dist/electron/window.js.map +1 -0
  65. package/dist/electron-preload.js +26 -6
  66. package/dist/electron-preload.js.map +1 -1
  67. package/dist/electron.js +6 -168
  68. package/dist/electron.js.map +1 -1
  69. package/dist/index.js +323 -266
  70. package/dist/llm/config-store.js +24 -8
  71. package/dist/llm/llm-judgment-client.js +102 -102
  72. package/dist/llm/pi-ai.js +137 -85
  73. package/dist/llm/system-prompt/layers/channel/local.md +14 -14
  74. package/dist/llm/system-prompt/layers/channel/p2p-agent.md +18 -18
  75. package/dist/llm/system-prompt/layers/channel/p2p-visitor.md +19 -19
  76. package/dist/llm/system-prompt/layers/core/artifacts_storage.md +89 -89
  77. package/dist/llm/system-prompt/layers/core/evenhandedness.md +21 -21
  78. package/dist/llm/system-prompt/layers/core/hibs_reminders.md +15 -15
  79. package/dist/llm/system-prompt/layers/core/identity.md +37 -37
  80. package/dist/llm/system-prompt/layers/core/knowledge.md +17 -17
  81. package/dist/llm/system-prompt/layers/core/memory_system.md +12 -12
  82. package/dist/llm/system-prompt/layers/core/network_filesystem.md +28 -28
  83. package/dist/llm/system-prompt/layers/core/refusal.md +37 -37
  84. package/dist/llm/system-prompt/layers/core/tone.md +31 -31
  85. package/dist/llm/system-prompt/layers/core/tools.thin.md +13 -13
  86. package/dist/llm/system-prompt/layers/core/wellbeing.md +41 -41
  87. package/dist/llm/system-prompt/layers/role/architect.md +20 -20
  88. package/dist/llm/system-prompt/layers/role/expert.md +19 -19
  89. package/dist/llm/system-prompt/layers/role/implementer.md +15 -15
  90. package/dist/llm/system-prompt/layers/role/security.md +15 -15
  91. package/dist/llm/system-prompt/layers/tool/artifacts.md +72 -72
  92. package/dist/llm/system-prompt/layers/tool/bash.md +25 -25
  93. package/dist/llm/system-prompt/layers/tool/hibs_api.md +171 -171
  94. package/dist/llm/system-prompt/layers/tool/image_search.md +70 -70
  95. package/dist/llm/system-prompt/layers/tool/manifest.md +89 -89
  96. package/dist/llm/system-prompt/layers/tool/mcp_apps.md +53 -53
  97. package/dist/llm/system-prompt/layers/tool/web_search.md +83 -83
  98. package/dist/llm/tool-manifest/ask_user_input.js +1 -1
  99. package/dist/llm/tool-manifest/bash.js +3 -3
  100. package/dist/llm/tool-manifest/create_file.js +4 -4
  101. package/dist/llm/tool-manifest/fetch_sports_data.js +3 -3
  102. package/dist/llm/tool-manifest/image_search.js +2 -2
  103. package/dist/llm/tool-manifest/mcp.js +2 -2
  104. package/dist/llm/tool-manifest/message_compose.js +3 -3
  105. package/dist/llm/tool-manifest/places.js +2 -2
  106. package/dist/llm/tool-manifest/present_files.js +1 -1
  107. package/dist/llm/tool-manifest/recipe.js +2 -2
  108. package/dist/llm/tool-manifest/str_replace.js +5 -5
  109. package/dist/llm/tool-manifest/view.js +3 -3
  110. package/dist/llm/tool-manifest/weather.js +4 -4
  111. package/dist/llm/tool-manifest/web.js +4 -4
  112. package/dist/network/local-inbox-bus.js +73 -0
  113. package/dist/network/p2p-outbox.js +161 -0
  114. package/dist/network/peer-fs.js +420 -0
  115. package/dist/network/peer-resource-bridge.js +216 -0
  116. package/dist/pi-ecosystem-judgment/causal-judge.js +51 -51
  117. package/dist/pi-ecosystem-judgment/cleanup.js +126 -0
  118. package/dist/pi-ecosystem-judgment/distill-prompt.js +42 -42
  119. package/dist/pi-ecosystem-judgment/distillation.js +14 -14
  120. package/dist/pi-ecosystem-judgment/human-value-store.js +45 -11
  121. package/dist/pi-ecosystem-judgment/monitor-gate.js +28 -28
  122. package/dist/pi-ecosystem-judgment/value-injection.js +102 -102
  123. package/dist/security/context-router-tool.js +15 -15
  124. package/dist/security/tool-gate.js +11 -0
  125. package/dist/web/api-config.html +520 -520
  126. package/dist/web/client-loop-status.js +220 -0
  127. package/dist/web/client.js +1677 -244
  128. package/dist/web/client.js.map +7 -0
  129. package/dist/web/components/wallet-viem.mjs +118 -118
  130. package/dist/web/index.html +375 -374
  131. package/dist/web/input-validator.js +103 -0
  132. package/dist/web/manifest.json +20 -20
  133. package/dist/web/routes-judgments.js +738 -0
  134. package/dist/web/routes-llm-config.js +279 -0
  135. package/dist/web/routes-tasks.js +222 -0
  136. package/dist/web/server-sse.js +121 -0
  137. package/dist/web/server-storage.js +154 -0
  138. package/dist/web/server-types.js +15 -0
  139. package/dist/web/server-v3-p2p.js +224 -0
  140. package/dist/web/server.js +1070 -1307
  141. package/dist/web/style.css +4742 -4737
  142. package/dist/web/util/safe-name.js +32 -0
  143. package/package.json +162 -160
  144. package/scripts/build-cli.js +215 -215
  145. package/scripts/build-web.ts +130 -125
  146. package/scripts/postinstall.js +152 -152
  147. package/bin/bolloon.js +0 -157
  148. package/dist/constraint-runtime/src/_archive_helper.js +0 -9
  149. package/dist/constraint-runtime/src/agent/coordinator.js +0 -48
  150. package/dist/constraint-runtime/src/agent/index.js +0 -1
  151. package/dist/constraint-runtime/src/assistant/index.js +0 -12
  152. package/dist/constraint-runtime/src/bootstrap/index.js +0 -12
  153. package/dist/constraint-runtime/src/bootstrap_graph.js +0 -13
  154. package/dist/constraint-runtime/src/bridge/index.js +0 -12
  155. package/dist/constraint-runtime/src/buddy/index.js +0 -12
  156. package/dist/constraint-runtime/src/cli/index.js +0 -12
  157. package/dist/constraint-runtime/src/command_graph.js +0 -10
  158. package/dist/constraint-runtime/src/commands.js +0 -60
  159. package/dist/constraint-runtime/src/components/index.js +0 -12
  160. package/dist/constraint-runtime/src/constants/index.js +0 -12
  161. package/dist/constraint-runtime/src/constraint/budget.js +0 -22
  162. package/dist/constraint-runtime/src/constraint/index.js +0 -2
  163. package/dist/constraint-runtime/src/constraint/permission.js +0 -20
  164. package/dist/constraint-runtime/src/context.js +0 -30
  165. package/dist/constraint-runtime/src/coordinator/index.js +0 -12
  166. package/dist/constraint-runtime/src/cost_hook.js +0 -4
  167. package/dist/constraint-runtime/src/cost_tracker.js +0 -8
  168. package/dist/constraint-runtime/src/deferred_init.js +0 -10
  169. package/dist/constraint-runtime/src/direct_modes.js +0 -6
  170. package/dist/constraint-runtime/src/dynamic-tool-loader.js +0 -85
  171. package/dist/constraint-runtime/src/entrypoints/index.js +0 -12
  172. package/dist/constraint-runtime/src/execution_registry.js +0 -44
  173. package/dist/constraint-runtime/src/history.js +0 -9
  174. package/dist/constraint-runtime/src/hooks/index.js +0 -12
  175. package/dist/constraint-runtime/src/index.js +0 -26
  176. package/dist/constraint-runtime/src/ink.js +0 -4
  177. package/dist/constraint-runtime/src/keybindings/index.js +0 -12
  178. package/dist/constraint-runtime/src/memdir/index.js +0 -12
  179. package/dist/constraint-runtime/src/migrations/index.js +0 -12
  180. package/dist/constraint-runtime/src/models.js +0 -1
  181. package/dist/constraint-runtime/src/moreright/index.js +0 -12
  182. package/dist/constraint-runtime/src/native_ts/index.js +0 -12
  183. package/dist/constraint-runtime/src/output_styles/index.js +0 -12
  184. package/dist/constraint-runtime/src/parity_audit.js +0 -12
  185. package/dist/constraint-runtime/src/plugins/index.js +0 -12
  186. package/dist/constraint-runtime/src/port_manifest.js +0 -11
  187. package/dist/constraint-runtime/src/prefetch.js +0 -9
  188. package/dist/constraint-runtime/src/query.js +0 -1
  189. package/dist/constraint-runtime/src/remote/index.js +0 -12
  190. package/dist/constraint-runtime/src/remote_runtime.js +0 -9
  191. package/dist/constraint-runtime/src/runtime/index.js +0 -1
  192. package/dist/constraint-runtime/src/runtime/session.js +0 -35
  193. package/dist/constraint-runtime/src/schemas/index.js +0 -12
  194. package/dist/constraint-runtime/src/screens/index.js +0 -12
  195. package/dist/constraint-runtime/src/server/index.js +0 -12
  196. package/dist/constraint-runtime/src/services/index.js +0 -12
  197. package/dist/constraint-runtime/src/session_store.js +0 -22
  198. package/dist/constraint-runtime/src/setup.js +0 -30
  199. package/dist/constraint-runtime/src/skills/index.js +0 -1
  200. package/dist/constraint-runtime/src/skills/skill-registry.js +0 -28
  201. package/dist/constraint-runtime/src/state/index.js +0 -12
  202. package/dist/constraint-runtime/src/system_init.js +0 -20
  203. package/dist/constraint-runtime/src/thinking/engine.js +0 -42
  204. package/dist/constraint-runtime/src/thinking/index.js +0 -1
  205. package/dist/constraint-runtime/src/tool_pool.js +0 -8
  206. package/dist/constraint-runtime/src/tools/OpenCLI/execAdapter.js +0 -7
  207. package/dist/constraint-runtime/src/tools/OpenCLI/listAdapters.js +0 -7
  208. package/dist/constraint-runtime/src/tools/OpenCLI/runCommand.js +0 -7
  209. package/dist/constraint-runtime/src/tools/SafeSDK/confirmTransaction.js +0 -6
  210. package/dist/constraint-runtime/src/tools/SafeSDK/createTransaction.js +0 -8
  211. package/dist/constraint-runtime/src/tools/SafeSDK/executeTransaction.js +0 -6
  212. package/dist/constraint-runtime/src/tools/SafeSDK/getBalance.js +0 -6
  213. package/dist/constraint-runtime/src/tools/SafeSDK/getPendingTransactions.js +0 -6
  214. package/dist/constraint-runtime/src/tools/SafeSDK/proposeTransaction.js +0 -6
  215. package/dist/constraint-runtime/src/tools.js +0 -80
  216. package/dist/constraint-runtime/src/transcript.js +0 -19
  217. package/dist/constraint-runtime/src/types/index.js +0 -12
  218. package/dist/constraint-runtime/src/upstream_proxy/index.js +0 -12
  219. package/dist/constraint-runtime/src/utils/index.js +0 -12
  220. package/dist/constraint-runtime/src/vim/index.js +0 -12
  221. package/dist/constraint-runtime/src/voice/index.js +0 -12
  222. package/dist/constraint-runtime/tests/agent.test.js +0 -16
  223. package/dist/constraint-runtime/tests/constraint.test.js +0 -41
  224. package/dist/constraint-runtime/tests/skill.test.js +0 -19
  225. package/dist/constraint-runtime/tests/thinking.test.js +0 -22
  226. package/dist/pi-ecosystem-colony/index.js +0 -365
  227. package/dist/social/ant-colony/AdaptiveHeartbeat.js +0 -101
  228. package/dist/social/ant-colony/PheromoneEngine.js +0 -227
  229. package/dist/social/ant-colony/index.js +0 -6
  230. package/dist/social/ant-colony/types.js +0 -24
  231. package/dist/test/ai-judgment-test.js +0 -80
  232. package/dist/test/bollharness-integration.test.js +0 -318
  233. package/dist/test/channel-agent-multi-dialogue.js +0 -205
  234. package/dist/test/channel-heartbeat-agent-test.js +0 -201
  235. package/dist/test/constraint-layer.test.js +0 -164
  236. package/dist/test/diap-identity-test.js +0 -172
  237. package/dist/test/diap-quick-test.js +0 -62
  238. package/dist/test/global-shared-context.test.js +0 -315
  239. package/dist/test/harness-judgment-injection.test.js +0 -246
  240. package/dist/test/harness-workflow-integrator-test.js +0 -228
  241. package/dist/test/human-value-store.test.js +0 -243
  242. package/dist/test/hybrid-integration-test.js +0 -118
  243. package/dist/test/hybrid-messenger-verify.js +0 -55
  244. package/dist/test/iroh-bistream-debug.js +0 -38
  245. package/dist/test/iroh-communication.test.js +0 -66
  246. package/dist/test/iroh-debug-test.js +0 -57
  247. package/dist/test/iroh-diap-test.js +0 -71
  248. package/dist/test/iroh-direct-connect.js +0 -55
  249. package/dist/test/iroh-e2e-fixed.js +0 -89
  250. package/dist/test/iroh-e2e-same-process.js +0 -63
  251. package/dist/test/iroh-e2e.js +0 -66
  252. package/dist/test/iroh-final-e2e.js +0 -72
  253. package/dist/test/iroh-relay-test.js +0 -37
  254. package/dist/test/iroh-simple-test.js +0 -41
  255. package/dist/test/iroh-transport-verify.js +0 -54
  256. package/dist/test/iroh-transport.test.js +0 -37
  257. package/dist/test/iroh-two-nodes.js +0 -70
  258. package/dist/test/iroh-verify.js +0 -44
  259. package/dist/test/judgment-decision.test.js +0 -219
  260. package/dist/test/llm-judgment-integration.test.js +0 -220
  261. package/dist/test/p2p-agent-complex-dialogue.js +0 -385
  262. package/dist/test/p2p-agent-dialogue.js +0 -341
  263. package/dist/test/p2p-agent-full-bidirectional.js +0 -510
  264. package/dist/test/p2p-agent-harness-flow.js +0 -437
  265. package/dist/test/p2p-agent-harness-single.js +0 -143
  266. package/dist/test/p2p-ai-dialogue-test.js +0 -318
  267. package/dist/test/p2p-cid-connect-test.js +0 -195
  268. package/dist/test/p2p-connect-receiver.js +0 -69
  269. package/dist/test/p2p-doc-transfer.js +0 -110
  270. package/dist/test/p2p-identity-page-test.js +0 -77
  271. package/dist/test/p2p-iroh-test.js +0 -171
  272. package/dist/test/p2p-minimal-test.js +0 -241
  273. package/dist/test/p2p-node-1.js +0 -148
  274. package/dist/test/p2p-node-2.js +0 -148
  275. package/dist/test/p2p-server.js +0 -281
  276. package/dist/test/p2p-two-nodes-test.js +0 -438
  277. package/dist/test/pi-sdk.test.js +0 -44
  278. package/dist/test/set-persona.js +0 -40
  279. package/dist/test/simple.test.js +0 -9
  280. package/dist/test/storage-integration.test.js +0 -150
  281. package/dist/test/subagent-manager.test.js +0 -276
  282. package/dist/test/test-gate-flow.test.js +0 -81
  283. package/dist/test/workflow-engine.test.js +0 -87
  284. package/dist/test/workflow-pivot-loop.test.js +0 -246
@@ -0,0 +1,279 @@
1
+ /**
2
+ * routes-llm-config.ts — LLM/Video/Audio 配置路由 (2026-07-06 抽出)
3
+ *
4
+ * 从 src/web/server.ts 抽出 (~230 行).
5
+ * 包含 /api/llm-config/* /api/video-config/* /api/audio-config/* /api/ai-parse
6
+ */
7
+ import { llmConfigStore } from '../llm/config-store.js';
8
+ import { videoConfigStore } from '../llm/video-config-store.js';
9
+ import { audioConfigStore } from '../llm/audio-config-store.js';
10
+ import { initMinimax, getMinimax } from '../constraints/index.js';
11
+ export function registerLlmConfigRoutes(app) {
12
+ // ==================== LLM 配置 API ====================
13
+ // 获取所有 LLM 配置
14
+ app.get('/api/llm-config', async (req, res) => {
15
+ try {
16
+ const config = await llmConfigStore.getConfig();
17
+ const providerInfo = llmConfigStore.getAllProviderInfo();
18
+ // 隐藏 API Key
19
+ const safeConfig = {
20
+ ...config,
21
+ providers: Object.fromEntries(Object.entries(config.providers).map(([key, val]) => [
22
+ key,
23
+ { ...val, apiKey: val.apiKey ? '***' + val.apiKey.slice(-4) : '' }
24
+ ])),
25
+ providerInfo
26
+ };
27
+ res.json(safeConfig);
28
+ }
29
+ catch (err) {
30
+ res.status(500).json({ error: err.message });
31
+ }
32
+ });
33
+ // 更新 LLM 配置
34
+ app.post('/api/llm-config', async (req, res) => {
35
+ try {
36
+ const { provider, config } = req.body;
37
+ if (!provider || !config) {
38
+ return res.status(400).json({ error: 'provider and config required' });
39
+ }
40
+ // 如果前端发的是掩码(***xxx),从当前配置里取真实 key
41
+ const currentConfig = await llmConfigStore.getProvider(provider);
42
+ if (currentConfig && config.apiKey && config.apiKey.startsWith('***')) {
43
+ config.apiKey = currentConfig.apiKey;
44
+ }
45
+ await llmConfigStore.updateProvider(provider, config);
46
+ // 如果是活跃供应商,重新初始化 Pi SDK
47
+ const currentActive = await llmConfigStore.getActiveProvider();
48
+ if (provider === currentActive) {
49
+ const newConfig = await llmConfigStore.getActiveProviderConfig();
50
+ if (newConfig) {
51
+ initMinimax({
52
+ provider,
53
+ apiKey: newConfig.apiKey || undefined,
54
+ baseUrl: newConfig.baseUrl || undefined,
55
+ model: newConfig.model || undefined
56
+ });
57
+ }
58
+ }
59
+ res.json({ ok: true });
60
+ }
61
+ catch (err) {
62
+ res.status(500).json({ error: err.message });
63
+ }
64
+ });
65
+ // 设置活跃供应商
66
+ app.post('/api/llm-provider', async (req, res) => {
67
+ try {
68
+ const { provider } = req.body;
69
+ if (!provider) {
70
+ return res.status(400).json({ error: 'provider required' });
71
+ }
72
+ await llmConfigStore.setActiveProvider(provider);
73
+ // 重新初始化 Pi SDK
74
+ const config = await llmConfigStore.getActiveProviderConfig();
75
+ if (config) {
76
+ initMinimax({
77
+ provider: provider,
78
+ apiKey: config.apiKey || undefined,
79
+ baseUrl: config.baseUrl || undefined,
80
+ model: config.model || undefined
81
+ });
82
+ }
83
+ res.json({ ok: true, provider });
84
+ }
85
+ catch (err) {
86
+ res.status(500).json({ error: err.message });
87
+ }
88
+ });
89
+ // 测试供应商连接
90
+ app.post('/api/llm-test', async (req, res) => {
91
+ try {
92
+ const { provider } = req.body;
93
+ if (!provider) {
94
+ return res.status(400).json({ error: 'provider required' });
95
+ }
96
+ const result = await llmConfigStore.testProvider(provider);
97
+ res.json(result);
98
+ }
99
+ catch (err) {
100
+ res.status(500).json({ error: err.message });
101
+ }
102
+ });
103
+ // ==================== 视频生成配置 (Seedance 等) ====================
104
+ // 获取视频生成配置
105
+ app.get('/api/video-config', async (req, res) => {
106
+ try {
107
+ const config = await videoConfigStore.getConfig();
108
+ const providerInfo = videoConfigStore.getAllProviderInfo();
109
+ // 脱敏:不返回 apiKey 明文
110
+ const masked = Object.fromEntries(Object.entries(config.providers).map(([key, val]) => [
111
+ key,
112
+ { ...val, apiKey: val.apiKey ? '***' + val.apiKey.slice(-4) : '' }
113
+ ]));
114
+ res.json({
115
+ activeProvider: config.activeProvider,
116
+ providers: masked,
117
+ providerInfo
118
+ });
119
+ }
120
+ catch (err) {
121
+ res.status(500).json({ error: err.message });
122
+ }
123
+ });
124
+ // 更新视频供应商配置
125
+ app.post('/api/video-config', async (req, res) => {
126
+ try {
127
+ const { provider, config } = req.body;
128
+ if (!provider || !config) {
129
+ return res.status(400).json({ error: 'provider and config required' });
130
+ }
131
+ // 如果前端发的是掩码(***xxx),从当前配置里取真实 key
132
+ const currentConfig = await videoConfigStore.getProvider(provider);
133
+ if (currentConfig && config.apiKey && config.apiKey.startsWith('***')) {
134
+ config.apiKey = currentConfig.apiKey;
135
+ }
136
+ await videoConfigStore.updateProvider(provider, config);
137
+ res.json({ ok: true });
138
+ }
139
+ catch (err) {
140
+ res.status(500).json({ error: err.message });
141
+ }
142
+ });
143
+ // 测试视频供应商连接
144
+ app.post('/api/video-test', async (req, res) => {
145
+ try {
146
+ const { provider } = req.body;
147
+ if (!provider) {
148
+ return res.status(400).json({ error: 'provider required' });
149
+ }
150
+ const result = await videoConfigStore.testProvider(provider);
151
+ res.json(result);
152
+ }
153
+ catch (err) {
154
+ res.status(500).json({ error: err.message });
155
+ }
156
+ });
157
+ // ==================== 音频生成配置 (TTS / Music) ====================
158
+ // 获取音频配置
159
+ app.get('/api/audio-config', async (req, res) => {
160
+ try {
161
+ const config = await audioConfigStore.getConfig();
162
+ const providerInfo = audioConfigStore.getAllProviderInfo();
163
+ const masked = Object.fromEntries(Object.entries(config.providers).map(([key, val]) => [
164
+ key,
165
+ { ...val, apiKey: val.apiKey ? '***' + val.apiKey.slice(-4) : '' }
166
+ ]));
167
+ res.json({
168
+ activeProvider: config.activeProvider,
169
+ providers: masked,
170
+ providerInfo
171
+ });
172
+ }
173
+ catch (err) {
174
+ res.status(500).json({ error: err.message });
175
+ }
176
+ });
177
+ // 更新音频供应商配置
178
+ app.post('/api/audio-config', async (req, res) => {
179
+ try {
180
+ const { provider, config } = req.body;
181
+ if (!provider || !config) {
182
+ return res.status(400).json({ error: 'provider and config required' });
183
+ }
184
+ // 掩码回写真实 key
185
+ const currentConfig = await audioConfigStore.getProvider(provider);
186
+ if (currentConfig && config.apiKey && config.apiKey.startsWith('***')) {
187
+ config.apiKey = currentConfig.apiKey;
188
+ }
189
+ await audioConfigStore.updateProvider(provider, config);
190
+ res.json({ ok: true });
191
+ }
192
+ catch (err) {
193
+ res.status(500).json({ error: err.message });
194
+ }
195
+ });
196
+ // 测试音频供应商连接
197
+ app.post('/api/audio-test', async (req, res) => {
198
+ try {
199
+ const { provider } = req.body;
200
+ if (!provider) {
201
+ return res.status(400).json({ error: 'provider required' });
202
+ }
203
+ const result = await audioConfigStore.testProvider(provider);
204
+ res.json(result);
205
+ }
206
+ catch (err) {
207
+ res.status(500).json({ error: err.message });
208
+ }
209
+ });
210
+ // 统一 AI 解析入口:CLI / 接收方节点 调这里完成 LLM + judgment + harness
211
+ // 入参: { text, mimeType, fileName, fromNodeId, source }
212
+ // 出参: { summary, qualityScore, judgmentId?, gateArtifact? }
213
+ app.post('/api/ai-parse', async (req, res) => {
214
+ try {
215
+ const { text, mimeType, fileName, fromNodeId, source } = req.body || {};
216
+ if (!text || !fileName) {
217
+ return res.status(400).json({ error: 'text and fileName required' });
218
+ }
219
+ const truncated = text.length > 6000 ? text.substring(0, 6000) + '...[截断]' : text;
220
+ const prompt = `请分析以下 ${mimeType || 'text'} 文档,并给出 (1) 一句话中文摘要 (2) 三个关键要点 (3) 质量评分(0-1)。\n\n文件名: ${fileName}\n\n内容:\n${truncated}`;
221
+ // 1. LLM 解析
222
+ const llm = getMinimax();
223
+ const t0 = Date.now();
224
+ const llmResult = await llm.summarize(prompt);
225
+ const dt = Date.now() - t0;
226
+ const out = {
227
+ ok: true,
228
+ summary: llmResult.summary,
229
+ qualityScore: llmResult.qualityScore,
230
+ latencyMs: dt,
231
+ mimeType: mimeType || 'text/plain',
232
+ fileName,
233
+ };
234
+ // 2. 蒸馏为 judgment (异步,失败不影响主返回)
235
+ try {
236
+ const judgmentMod = await import('../pi-ecosystem-judgment/index.js');
237
+ await judgmentMod.initializeJudgmentStore();
238
+ const j = await judgmentMod.createJudgment({
239
+ type: 'trajectory',
240
+ content: `AI 解析 ${fileName}: ${llmResult.summary.slice(0, 200)}`,
241
+ source: 'agent',
242
+ confidence: Math.min(1, llmResult.qualityScore),
243
+ context: `ai-parse:${mimeType || 'text'}:${source || 'p2p'}`,
244
+ evidence: {
245
+ trajectory: [{
246
+ timestamp: new Date().toISOString(),
247
+ action: `parse:${fileName}`,
248
+ outcome: `score=${llmResult.qualityScore.toFixed(2)}`,
249
+ approved: true,
250
+ }],
251
+ },
252
+ });
253
+ out.judgmentId = j.id;
254
+ }
255
+ catch (e) {
256
+ out.judgmentError = e.message;
257
+ }
258
+ // 3. 在 harness 落产物 (异步,失败不影响)
259
+ try {
260
+ const harnessMod = await import('../bollharness-integration/index.js');
261
+ const gate = new harnessMod.GateStateMachine();
262
+ gate.submitArtifact(`ai-parse:${fileName}`, {
263
+ summary: llmResult.summary,
264
+ score: llmResult.qualityScore,
265
+ fromNodeId: fromNodeId || null,
266
+ parsedAt: Date.now(),
267
+ });
268
+ out.gateArtifact = `ai-parse:${fileName}`;
269
+ }
270
+ catch (e) {
271
+ out.gateError = e.message;
272
+ }
273
+ res.json(out);
274
+ }
275
+ catch (err) {
276
+ res.status(500).json({ error: err.message });
277
+ }
278
+ });
279
+ }
@@ -0,0 +1,222 @@
1
+ /**
2
+ * routes-tasks.ts — 任务队列 CRUD 路由 (2026-07-06 抽出)
3
+ *
4
+ * 从 src/web/server.ts 抽出 (~160 行).
5
+ * 包含 /api/tasks/* (GET, POST, PATCH, DELETE, execute, execute-next)
6
+ */
7
+ import { loadTaskQueue, saveTaskQueue, isTaskExecuting } from './server-storage.js';
8
+ import { documentReader } from '../documents/reader.js';
9
+ export function registerTaskRoutes(app, opts) {
10
+ const { broadcast, getAgentForChannel } = opts;
11
+ // 获取所有任务
12
+ app.get('/api/tasks', async (req, res) => {
13
+ try {
14
+ const tasks = await loadTaskQueue();
15
+ res.json(tasks);
16
+ }
17
+ catch (err) {
18
+ res.status(500).json({ error: err.message });
19
+ }
20
+ });
21
+ // 创建新任务
22
+ app.post('/api/tasks', async (req, res) => {
23
+ try {
24
+ const { type, title, description, steps } = req.body;
25
+ if (!type || !title) {
26
+ return res.status(400).json({ error: 'type and title required' });
27
+ }
28
+ const tasks = await loadTaskQueue();
29
+ const task = {
30
+ id: `task_${Date.now()}_${Math.random().toString(36).substring(2, 8)}`,
31
+ type,
32
+ title,
33
+ description,
34
+ status: 'pending',
35
+ progress: 0,
36
+ createdAt: new Date().toISOString(),
37
+ updatedAt: new Date().toISOString(),
38
+ steps: steps?.map((s, i) => ({
39
+ id: `step_${i}`,
40
+ name: s,
41
+ status: 'pending'
42
+ }))
43
+ };
44
+ tasks.push(task);
45
+ await saveTaskQueue(tasks);
46
+ res.json(task);
47
+ }
48
+ catch (err) {
49
+ res.status(500).json({ error: err.message });
50
+ }
51
+ });
52
+ // 获取单个任务
53
+ app.get('/api/tasks/:taskId', async (req, res) => {
54
+ try {
55
+ const { taskId } = req.params;
56
+ const tasks = await loadTaskQueue();
57
+ const task = tasks.find(t => t.id === taskId);
58
+ if (!task) {
59
+ return res.status(404).json({ error: 'Task not found' });
60
+ }
61
+ res.json(task);
62
+ }
63
+ catch (err) {
64
+ res.status(500).json({ error: err.message });
65
+ }
66
+ });
67
+ // 更新任务
68
+ app.patch('/api/tasks/:taskId', async (req, res) => {
69
+ try {
70
+ const { taskId } = req.params;
71
+ const { status, currentStep } = req.body;
72
+ const tasks = await loadTaskQueue();
73
+ const taskIndex = tasks.findIndex(t => t.id === taskId);
74
+ if (taskIndex === -1) {
75
+ return res.status(404).json({ error: 'Task not found' });
76
+ }
77
+ if (status) {
78
+ tasks[taskIndex].status = status;
79
+ }
80
+ if (currentStep !== undefined) {
81
+ tasks[taskIndex].currentStep = currentStep;
82
+ }
83
+ tasks[taskIndex].updatedAt = new Date().toISOString();
84
+ await saveTaskQueue(tasks);
85
+ res.json(tasks[taskIndex]);
86
+ }
87
+ catch (err) {
88
+ res.status(500).json({ error: err.message });
89
+ }
90
+ });
91
+ // 删除任务
92
+ app.delete('/api/tasks/:taskId', async (req, res) => {
93
+ try {
94
+ const { taskId } = req.params;
95
+ const tasks = await loadTaskQueue();
96
+ const filtered = tasks.filter(t => t.id !== taskId);
97
+ await saveTaskQueue(filtered);
98
+ res.json({ ok: true });
99
+ }
100
+ catch (err) {
101
+ res.status(500).json({ error: err.message });
102
+ }
103
+ });
104
+ // 执行任务(自动执行下一步)
105
+ app.post('/api/tasks/:taskId/execute', async (req, res) => {
106
+ try {
107
+ const { taskId } = req.params;
108
+ const { channelId } = req.body;
109
+ if (!channelId) {
110
+ return res.status(400).json({ error: 'channelId required' });
111
+ }
112
+ const tasks = await loadTaskQueue();
113
+ const task = tasks.find(t => t.id === taskId);
114
+ if (!task) {
115
+ return res.status(404).json({ error: 'Task not found' });
116
+ }
117
+ if (isTaskExecuting()) {
118
+ return res.status(409).json({ error: 'Another task is currently executing' });
119
+ }
120
+ // 异步执行任务
121
+ executeTask(task, channelId, getAgentForChannel, broadcast);
122
+ res.json({ ok: true, taskId: task.id });
123
+ }
124
+ catch (err) {
125
+ res.status(500).json({ error: err.message });
126
+ }
127
+ });
128
+ // 执行下一个待处理任务
129
+ app.post('/api/tasks/execute-next', async (req, res) => {
130
+ try {
131
+ const { channelId } = req.body;
132
+ if (!channelId) {
133
+ return res.status(400).json({ error: 'channelId required' });
134
+ }
135
+ const tasks = await loadTaskQueue();
136
+ const nextTask = tasks.find(t => t.status === 'pending');
137
+ if (!nextTask) {
138
+ return res.json({ ok: false, message: 'No pending tasks' });
139
+ }
140
+ if (isTaskExecuting()) {
141
+ return res.status(409).json({ error: 'Another task is currently executing' });
142
+ }
143
+ // 异步执行任务
144
+ executeTask(nextTask, channelId, getAgentForChannel, broadcast);
145
+ res.json({ ok: true, taskId: nextTask.id });
146
+ }
147
+ catch (err) {
148
+ res.status(500).json({ error: err.message });
149
+ }
150
+ });
151
+ }
152
+ // ==================== Task Execution ====================
153
+ async function executeTask(task, channelId, getAgentForChannel, broadcast) {
154
+ // 使用 server-storage 的 startTaskExecution 做锁
155
+ const { startTaskExecution, endTaskExecution } = await import('./server-storage.js');
156
+ if (!startTaskExecution(task.id))
157
+ return;
158
+ const agent = await getAgentForChannel(channelId);
159
+ const tasks = await loadTaskQueue();
160
+ const taskIndex = tasks.findIndex(t => t.id === task.id);
161
+ if (taskIndex >= 0) {
162
+ tasks[taskIndex].status = 'running';
163
+ tasks[taskIndex].updatedAt = new Date().toISOString();
164
+ await saveTaskQueue(tasks);
165
+ }
166
+ broadcast({ type: 'task_status', taskId: task.id, status: 'running', progress: 0 }, channelId);
167
+ try {
168
+ let result = '';
169
+ switch (task.type) {
170
+ case 'chat':
171
+ if (task.description) {
172
+ broadcast({ type: 'status', content: `执行任务: ${task.title}` }, channelId);
173
+ result = await agent.prompt(task.description);
174
+ }
175
+ break;
176
+ case 'read':
177
+ if (task.description) {
178
+ broadcast({ type: 'status', content: `读取文档: ${task.description}` }, channelId);
179
+ const content = await documentReader.read(task.description);
180
+ result = `📄 文档读取完成\n\n${content.text.substring(0, 500)}${content.text.length > 500 ? '...' : ''}`;
181
+ }
182
+ break;
183
+ case 'summarize':
184
+ if (task.description) {
185
+ broadcast({ type: 'status', content: `总结文档: ${task.description}` }, channelId);
186
+ const content = await documentReader.read(task.description);
187
+ const { getMinimax } = await import('../constraints/index.js');
188
+ const llm = getMinimax();
189
+ const summary = await llm.summarize(content.text);
190
+ result = `📝 文档总结:\n\n${summary.summary}`;
191
+ }
192
+ break;
193
+ default:
194
+ result = '未知任务类型';
195
+ }
196
+ // 更新任务状态
197
+ const tasks = await loadTaskQueue();
198
+ const idx = tasks.findIndex(t => t.id === task.id);
199
+ if (idx >= 0) {
200
+ tasks[idx].status = 'completed';
201
+ tasks[idx].progress = 100;
202
+ tasks[idx].result = result;
203
+ tasks[idx].updatedAt = new Date().toISOString();
204
+ await saveTaskQueue(tasks);
205
+ }
206
+ broadcast({ type: 'task_status', taskId: task.id, status: 'completed', progress: 100, result }, channelId);
207
+ broadcast({ type: 'ai', content: result }, channelId);
208
+ }
209
+ catch (error) {
210
+ const tasks = await loadTaskQueue();
211
+ const idx = tasks.findIndex(t => t.id === task.id);
212
+ if (idx >= 0) {
213
+ tasks[idx].status = 'failed';
214
+ tasks[idx].error = error.message;
215
+ tasks[idx].updatedAt = new Date().toISOString();
216
+ await saveTaskQueue(tasks);
217
+ }
218
+ broadcast({ type: 'task_status', taskId: task.id, status: 'failed', error: error.message }, channelId);
219
+ broadcast({ type: 'error', content: `任务执行失败: ${error.message}` }, channelId);
220
+ }
221
+ endTaskExecution();
222
+ }
@@ -0,0 +1,121 @@
1
+ /**
2
+ * server-sse.ts — server.ts 拆出的 SSE 实时推送层
3
+ *
4
+ * 包含:
5
+ * - sseClients: 客户端连接 Set
6
+ * - broadcast(): 推 SSE 事件 + 加 seq/msgId envelope
7
+ * - nextEventSeq / nextMsgId: 用于客户端断线重连 resume
8
+ * - installChatBusHook / installSelfImproveHook: 桥接 chat event bus / self-improve bus → SSE
9
+ *
10
+ * 从 src/web/server.ts 抽出 (2026-07-06).
11
+ * SSEClient type 来自 ./server-types.ts.
12
+ */
13
+ import * as crypto from 'crypto';
14
+ const sseClients = new Set();
15
+ export function getSseClients() {
16
+ return sseClients;
17
+ }
18
+ export function addSseClient(client) {
19
+ sseClients.add(client);
20
+ }
21
+ export function removeSseClient(client) {
22
+ sseClients.delete(client);
23
+ }
24
+ // 2026-07-06: 每个 channelId 维护递增 sequence + msgId, 让前端能去重 + 重连后 resume
25
+ const channelEventSeq = new Map();
26
+ const channelMsgIds = new Map(); // channelId -> 上一条 msgId (uuid)
27
+ export function nextEventSeq(channelId) {
28
+ if (!channelId)
29
+ return 0;
30
+ const cur = channelEventSeq.get(channelId) || 0;
31
+ const next = cur + 1;
32
+ channelEventSeq.set(channelId, next);
33
+ return next;
34
+ }
35
+ export function nextMsgId(channelId) {
36
+ const id = `msg_${Date.now()}_${crypto.randomBytes(4).toString('hex')}`;
37
+ if (channelId)
38
+ channelMsgIds.set(channelId, id);
39
+ return id;
40
+ }
41
+ /**
42
+ * 给 watchdog 喂活动, 让 broadcast() / 模块级业务函数能埋点喂活动
43
+ * 之前在 createWebServer 闭包内, 闭包外的 broadcast() 拿不到 → 误判 30min 无活动 → 自杀.
44
+ */
45
+ let watchdogRef = null;
46
+ export function setWatchdogRef(ref) {
47
+ watchdogRef = ref;
48
+ }
49
+ export function broadcast(data, channelId) {
50
+ watchdogRef?.recordActivity?.();
51
+ const seq = nextEventSeq(channelId);
52
+ const msgId = (data.type === 'ai' || data.type === 'user')
53
+ ? nextMsgId(channelId)
54
+ : `evt_${Date.now()}_${crypto.randomBytes(4).toString('hex')}`;
55
+ const envelope = { ...data, channelId, seq, msgId };
56
+ const message = `data: ${JSON.stringify(envelope)}\n\n`;
57
+ console.log(`[broadcast] type=${data.type}, channelId=${channelId}, seq=${seq}, msgId=${msgId}, clients=${sseClients.size}`);
58
+ for (const client of sseClients) {
59
+ if (!channelId || client.channelId === channelId) {
60
+ try {
61
+ client.res.write(message);
62
+ }
63
+ catch (e) {
64
+ console.error(`[broadcast] 写入失败:`, e.message);
65
+ }
66
+ }
67
+ }
68
+ }
69
+ // ============================================================================
70
+ // Chat 事件总线 -> SSE 桥 (供前端 inbox UI 用)
71
+ // ============================================================================
72
+ let chatBusHookInstalled = false;
73
+ export async function installChatBusHook() {
74
+ if (chatBusHookInstalled)
75
+ return;
76
+ chatBusHookInstalled = true;
77
+ try {
78
+ const { chatEventBus } = await import('../agents/p2p-chat-tools.js');
79
+ chatEventBus.on('chat', (ev) => {
80
+ broadcast({ type: 'chat_event', chatKind: ev.kind, payload: ev }, undefined);
81
+ });
82
+ console.log('[chat-bus] SSE bridge installed');
83
+ }
84
+ catch (e) {
85
+ console.warn('[chat-bus] install failed:', e.message);
86
+ }
87
+ }
88
+ // ============================================================================
89
+ // Self-Improve Bus -> SSE 桥 (供前端 / 用户看到自改触发)
90
+ // ============================================================================
91
+ let selfImproveHookInstalled = false;
92
+ export async function installSelfImproveHook() {
93
+ if (selfImproveHookInstalled)
94
+ return;
95
+ selfImproveHookInstalled = true;
96
+ try {
97
+ const { onSelfImproveTrigger } = await import('../heartbeat/self-improve-bus.js');
98
+ const { runSelfImproveLoop } = await import('../agents/pi-sdk.js');
99
+ onSelfImproveTrigger(async (event, goal) => {
100
+ broadcast({
101
+ type: 'self_improve_triggered',
102
+ eventKind: event.kind,
103
+ details: event.details,
104
+ goal,
105
+ ts: Date.now()
106
+ }, undefined);
107
+ const result = await runSelfImproveLoop(goal);
108
+ broadcast({
109
+ type: 'self_improve_result',
110
+ success: result.success,
111
+ output: result.output,
112
+ error: result.error,
113
+ ts: Date.now()
114
+ }, undefined);
115
+ });
116
+ console.log('[self-improve] SSE bridge installed');
117
+ }
118
+ catch (e) {
119
+ console.warn('[self-improve] install failed:', e.message);
120
+ }
121
+ }