@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
@@ -0,0 +1,437 @@
1
+ /**
2
+ * P2P Agent with Harness Full Flow Test
3
+ * 测试两个智能体通过 P2P 进行有意义对话,并基于判断力调用 Harness
4
+ *
5
+ * 运行: npx tsx src/test/p2p-agent-harness-flow.ts
6
+ */
7
+ import { config } from 'dotenv';
8
+ import express from 'express';
9
+ import { createServer } from 'http';
10
+ import crypto from 'crypto';
11
+ config();
12
+ const PORT_ALICE = 4001;
13
+ const PORT_BOB = 4002;
14
+ class HarnessCore {
15
+ gateHistory = new Map();
16
+ // 判断是否需要调用 Harness
17
+ decide(context, agentId) {
18
+ const lowerContext = context.toLowerCase();
19
+ // 检查是否涉及需要 Harness 的关键词
20
+ const decisionKeywords = [
21
+ '分析', '检查', '审核', '验证', '确认', '评估',
22
+ '决定', '选择', '计划', '架构', '设计',
23
+ '修复', '改进', '优化', '重构',
24
+ '测试', '部署', '发布',
25
+ '安全', '性能', '质量',
26
+ 'git', 'commit', 'review', 'merge'
27
+ ];
28
+ const matchedKeywords = decisionKeywords.filter(k => lowerContext.includes(k));
29
+ if (matchedKeywords.length > 0) {
30
+ const gate = this.determineGate(matchedKeywords);
31
+ return {
32
+ shouldCall: true,
33
+ gate,
34
+ reason: `检测到关键词: ${matchedKeywords.join(', ')}`,
35
+ action: this.getGateAction(gate)
36
+ };
37
+ }
38
+ return {
39
+ shouldCall: false,
40
+ gate: 0,
41
+ reason: '上下文无需 Harness 处理'
42
+ };
43
+ }
44
+ determineGate(keywords) {
45
+ const gateMap = {
46
+ '架构': 1, '设计': 1,
47
+ '审核': 2, 'review': 2, '检查': 2,
48
+ '计划': 3, '决定': 3, '选择': 3,
49
+ '任务': 5, '分解': 5,
50
+ '执行': 7, '修复': 7, '改进': 7, '优化': 7,
51
+ '测试': 8, '部署': 8, '发布': 8,
52
+ '安全': 4, '验证': 4,
53
+ 'git': 2, 'commit': 2, 'merge': 2
54
+ };
55
+ let maxGate = 0;
56
+ for (const kw of keywords) {
57
+ const gate = gateMap[kw] || 0;
58
+ if (gate > maxGate)
59
+ maxGate = gate;
60
+ }
61
+ return maxGate || 1; // 默认 Gate 1
62
+ }
63
+ getGateAction(gate) {
64
+ const actions = {
65
+ 0: '无需操作',
66
+ 1: '执行架构检查',
67
+ 2: '执行代码审查',
68
+ 3: '执行计划冻结',
69
+ 4: '执行安全验证',
70
+ 5: '执行任务分解',
71
+ 6: '执行 Guard 检查',
72
+ 7: '执行代码修改',
73
+ 8: '执行测试部署'
74
+ };
75
+ return actions[gate] || '执行通用检查';
76
+ }
77
+ // 执行 Harness 流程
78
+ execute(gate, context) {
79
+ const skills = this.getGateSkills(gate);
80
+ console.log(`\n🔧 [Harness] 执行 Gate ${gate}:`);
81
+ console.log(` Context: ${context.substring(0, 50)}...`);
82
+ console.log(` Skills: ${skills.join(', ')}`);
83
+ // 模拟不同 Gate 的处理
84
+ let result = '';
85
+ switch (gate) {
86
+ case 1:
87
+ result = this.executeArchitectureCheck(context);
88
+ break;
89
+ case 2:
90
+ result = this.executeCodeReview(context);
91
+ break;
92
+ case 3:
93
+ result = this.executePlanFreeze(context);
94
+ break;
95
+ case 5:
96
+ result = this.executeTaskArch(context);
97
+ break;
98
+ case 7:
99
+ result = this.executeCodeModify(context);
100
+ break;
101
+ case 8:
102
+ result = this.executeTestDeploy(context);
103
+ break;
104
+ default:
105
+ result = this.executeGenericCheck(context);
106
+ }
107
+ return {
108
+ success: true,
109
+ gate,
110
+ skills,
111
+ result,
112
+ message: `Gate ${gate} 处理完成`
113
+ };
114
+ }
115
+ getGateSkills(gate) {
116
+ const skillsMap = {
117
+ 0: [],
118
+ 1: ['arch', 'lead'],
119
+ 2: ['arch', 'guardian-fixer'],
120
+ 3: ['harness-eng', 'plan-lock'],
121
+ 4: ['arch', 'guardian-fixer'],
122
+ 5: ['task-arch', 'crystal-learn'],
123
+ 6: ['guardian-fixer'],
124
+ 7: ['harness-eng', 'crystal-learn'],
125
+ 8: ['harness-eng', 'harness-eng-test']
126
+ };
127
+ return skillsMap[gate] || ['arch', 'lead'];
128
+ }
129
+ executeArchitectureCheck(ctx) {
130
+ return `[架构检查] 分析完成\n建议: 分离关注点,使用接口隔离依赖`;
131
+ }
132
+ executeCodeReview(ctx) {
133
+ return `[代码审查] 检查完成\n建议: 添加错误处理,优化命名规范`;
134
+ }
135
+ executePlanFreeze(ctx) {
136
+ return `[计划冻结] 确认完成\n计划已锁定,等待执行`;
137
+ }
138
+ executeTaskArch(ctx) {
139
+ return `[任务分解] 完成\n分解为 3 个子任务,已分配优先级`;
140
+ }
141
+ executeCodeModify(ctx) {
142
+ return `[代码修改] 完成\n已应用修改,代码质量提升`;
143
+ }
144
+ executeTestDeploy(ctx) {
145
+ return `[测试部署] 完成\n测试通过,部署就绪`;
146
+ }
147
+ executeGenericCheck(ctx) {
148
+ return `[通用检查] 完成\n建议: 保持代码一致性`;
149
+ }
150
+ recordGate(agentId, gate) {
151
+ this.gateHistory.set(agentId, gate);
152
+ }
153
+ getGateHistory(agentId) {
154
+ return this.gateHistory.get(agentId) || 0;
155
+ }
156
+ }
157
+ class Agent {
158
+ id;
159
+ name;
160
+ port;
161
+ harness;
162
+ peers = new Map();
163
+ messageHistory = [];
164
+ httpServer = null;
165
+ processingReply = new Set(); // 防止重复处理同一条消息
166
+ constructor(name, port) {
167
+ this.id = crypto.randomUUID();
168
+ this.name = name;
169
+ this.port = port;
170
+ this.harness = new HarnessCore();
171
+ }
172
+ async start() {
173
+ const app = express();
174
+ app.use(express.json());
175
+ // 健康检查
176
+ app.get('/health', (req, res) => {
177
+ res.json({
178
+ id: this.id,
179
+ name: this.name,
180
+ port: this.port,
181
+ peers: Array.from(this.peers.keys()),
182
+ messageCount: this.messageHistory.length
183
+ });
184
+ });
185
+ // 发现端点
186
+ app.get('/discovery', (req, res) => {
187
+ res.json({
188
+ id: this.id,
189
+ name: this.name,
190
+ port: this.port,
191
+ topic: 'bolloon-agent-harness'
192
+ });
193
+ });
194
+ // 接收消息
195
+ app.post('/message', async (req, res) => {
196
+ const { fromName, content, messageId } = req.body;
197
+ // 使用 messageId 或 content hash 来去重,避免处理自己的回复
198
+ const msgKey = messageId || `${fromName}:${content.substring(0, 30)}`;
199
+ if (this.processingReply.has(msgKey)) {
200
+ return res.json({ ok: true, skipped: true });
201
+ }
202
+ this.processingReply.add(msgKey);
203
+ setTimeout(() => this.processingReply.delete(msgKey), 3000);
204
+ console.log(`\n📨 [${this.name}] 收到来自 ${fromName} 的消息:`);
205
+ console.log(` "${content.substring(0, 60)}..."`);
206
+ // 分析消息,决定是否调用 Harness
207
+ const decision = this.harness.decide(content, this.id);
208
+ let response = '';
209
+ let harnessResult;
210
+ if (decision.shouldCall) {
211
+ console.log(`\n🧠 [${this.name}] 判断力决策: 需要调用 Harness`);
212
+ console.log(` 原因: ${decision.reason}`);
213
+ console.log(` 行动: ${decision.action}`);
214
+ // 调用 Harness
215
+ harnessResult = this.harness.execute(decision.gate, content);
216
+ this.harness.recordGate(this.id, decision.gate);
217
+ // 生成基于 Harness 结果的回复
218
+ response = this.generateResponseFromHarness(content, harnessResult);
219
+ }
220
+ else {
221
+ console.log(`\n🧠 [${this.name}] 判断力决策: 无需 Harness`);
222
+ console.log(` 原因: ${decision.reason}`);
223
+ response = this.generateNaturalResponse(content);
224
+ }
225
+ // 保存消息(标记为非回复)
226
+ const msg = {
227
+ id: crypto.randomUUID(),
228
+ from: fromName,
229
+ to: this.name,
230
+ content,
231
+ timestamp: Date.now(),
232
+ isReply: false,
233
+ requiresHarness: decision.shouldCall,
234
+ harnessResult
235
+ };
236
+ this.messageHistory.push(msg);
237
+ // 发送回复(添加唯一 messageId 防止循环)
238
+ const peerPort = Array.from(this.peers.entries())[0]?.[1];
239
+ if (peerPort) {
240
+ const replyMsgId = crypto.randomUUID();
241
+ await this.sendMessage(peerPort, fromName, response, replyMsgId);
242
+ }
243
+ res.json({ ok: true, response, messageId: replyMsgId });
244
+ });
245
+ // 发现邻居
246
+ app.get('/nodes', (req, res) => {
247
+ const nodes = Array.from(this.peers.entries()).map(([id, port]) => ({
248
+ id,
249
+ name: this.peers.get(id) === port ? id : 'unknown',
250
+ port
251
+ }));
252
+ nodes.push({ id: this.id, name: this.name, port: this.port });
253
+ res.json(nodes);
254
+ });
255
+ this.httpServer = createServer(app);
256
+ return new Promise((resolve, reject) => {
257
+ this.httpServer.listen(this.port, () => {
258
+ console.log(`\n✓ [${this.name}] 启动成功 on port ${this.port}`);
259
+ resolve();
260
+ });
261
+ this.httpServer.on('error', reject);
262
+ });
263
+ }
264
+ generateResponseFromHarness(content, result) {
265
+ const responses = [
266
+ `根据 Harness Gate ${result.gate} 的分析:\n${result.result}\n\n建议: ${result.message}`,
267
+ `Harness 处理完成 (Gate ${result.gate}, Skills: ${result.skills.join(', ')})\n\n${result.result}`,
268
+ `经过 ${result.gate} 阶段审查:\n${result.result}\n\n状态: ${result.message}`
269
+ ];
270
+ return responses[Math.floor(Math.random() * responses.length)];
271
+ }
272
+ generateNaturalResponse(content) {
273
+ const lowerContent = content.toLowerCase();
274
+ if (lowerContent.includes('你好') || lowerContent.includes('hi') || lowerContent.includes('hello')) {
275
+ return `你好!我是 ${this.name},有什么我可以帮助的吗?`;
276
+ }
277
+ if (lowerContent.includes('?') || lowerContent.includes('?') || lowerContent.includes('怎么') || lowerContent.includes('如何')) {
278
+ return `好问题!让我帮你分析一下...(但这个问题不需要调用 Harness 进行深度分析)`;
279
+ }
280
+ return `收到!这个问题比较简单,我可以直接回答。`;
281
+ }
282
+ async sendMessage(toPort, toName, content, messageId) {
283
+ try {
284
+ await fetch(`http://localhost:${toPort}/message`, {
285
+ method: 'POST',
286
+ headers: { 'Content-Type': 'application/json' },
287
+ body: JSON.stringify({
288
+ fromName: this.name,
289
+ content,
290
+ messageId
291
+ })
292
+ });
293
+ }
294
+ catch (err) {
295
+ console.log(`[${this.name}] 发送失败:`, err);
296
+ }
297
+ }
298
+ async discoverPeers() {
299
+ const ports = [4001, 4002, 4003, 4004, 4005];
300
+ for (const port of ports) {
301
+ if (port === this.port)
302
+ continue;
303
+ try {
304
+ const resp = await fetch(`http://localhost:${port}/discovery`, {
305
+ signal: AbortSignal.timeout(1000)
306
+ });
307
+ if (resp.ok) {
308
+ const info = await resp.json();
309
+ if (info.id !== this.id && !this.peers.has(info.id)) {
310
+ console.log(`\n🔍 [${this.name}] 发现邻居: ${info.name} on port ${info.port}`);
311
+ this.peers.set(info.id, info.port);
312
+ }
313
+ }
314
+ }
315
+ catch { }
316
+ }
317
+ }
318
+ getMessageHistory() {
319
+ return [...this.messageHistory];
320
+ }
321
+ async stop() {
322
+ if (this.httpServer) {
323
+ await new Promise(resolve => this.httpServer.close(resolve));
324
+ }
325
+ }
326
+ }
327
+ // ============================================================================
328
+ // 测试场景
329
+ // ============================================================================
330
+ async function runFullFlowTest() {
331
+ console.log('\n========================================');
332
+ console.log(' P2P Agent + Harness Full Flow Test');
333
+ console.log('========================================\n');
334
+ // 创建两个智能体
335
+ const alice = new Agent('Alice', PORT_ALICE);
336
+ const bob = new Agent('Bob', PORT_BOB);
337
+ console.log('━━━ 步骤 1: 启动智能体 ━━━\n');
338
+ await alice.start();
339
+ await bob.start();
340
+ // 等待节点发现
341
+ console.log('\n━━━ 步骤 2: 节点发现 ━━━\n');
342
+ await new Promise(resolve => setTimeout(resolve, 2000));
343
+ await alice.discoverPeers();
344
+ await bob.discoverPeers();
345
+ console.log(`[Alice] 发现 ${alice.peers.size} 个邻居`);
346
+ console.log(`[Bob] 发现 ${bob.peers.size} 个邻居`);
347
+ if (alice.peers.size === 0 || bob.peers.size === 0) {
348
+ console.log('\n⚠️ 邻居未发现,尝试手动连接...');
349
+ const alicePort = PORT_BOB; // Alice 连接到 Bob
350
+ const bobPort = PORT_ALICE; // Bob 连接到 Alice
351
+ const alicePeerId = Array.from(bob.peers?.keys?.() || [])[0];
352
+ const bobPeerId = Array.from(alice.peers?.keys?.() || [])[0];
353
+ // 手动设置邻居关系
354
+ alice.peers.set('bob-manual', PORT_BOB);
355
+ bob.peers.set('alice-manual', PORT_ALICE);
356
+ }
357
+ console.log('\n━━━ 步骤 3: 开始对话 ━━━\n');
358
+ // 对话场景 1: 需要 Harness 的架构问题
359
+ console.log('━━━ 对话 1: 架构分析 (需要 Harness) ━━━\n');
360
+ const msg1 = 'Bob,我需要分析一下我们项目的架构设计,看看有没有需要改进的地方?';
361
+ console.log(`[Alice] >>> ${msg1}`);
362
+ await alice.sendMessage(PORT_BOB, 'Bob', msg1);
363
+ // 等待 Bob 处理
364
+ await new Promise(resolve => setTimeout(resolve, 3000));
365
+ // 对话场景 2: 简单的问候 (不需要 Harness)
366
+ console.log('\n━━━ 对话 2: 简单问候 (不需要 Harness) ━━━\n');
367
+ const msg2 = 'Bob,最近怎么样?';
368
+ console.log(`[Alice] >>> ${msg2}`);
369
+ await alice.sendMessage(PORT_BOB, 'Bob', msg2);
370
+ // 等待 Bob 处理
371
+ await new Promise(resolve => setTimeout(resolve, 2000));
372
+ // 对话场景 3: 代码审查请求 (需要 Harness)
373
+ console.log('\n━━━ 对话 3: 代码审查 (需要 Harness) ━━━\n');
374
+ const msg3 = 'Bob,我写了一段代码,帮我 review 一下,特别是错误处理部分。';
375
+ console.log(`[Alice] >>> ${msg3}`);
376
+ await alice.sendMessage(PORT_BOB, 'Bob', msg3);
377
+ // 等待 Bob 处理
378
+ await new Promise(resolve => setTimeout(resolve, 3000));
379
+ // 对话场景 4: 任务分解 (需要 Harness)
380
+ console.log('\n━━━ 对话 4: 任务分解 (需要 Harness) ━━━\n');
381
+ const msg4 = 'Bob,我们需要完成一个功能:用户登录系统。请帮我分解一下任务。';
382
+ console.log(`[Alice] >>> ${msg4}`);
383
+ await alice.sendMessage(PORT_BOB, 'Bob', msg4);
384
+ // 等待 Bob 处理
385
+ await new Promise(resolve => setTimeout(resolve, 3000));
386
+ // 对话场景 5: 闲聊 (不需要 Harness)
387
+ console.log('\n━━━ 对话 5: 闲聊 (不需要 Harness) ━━━\n');
388
+ const msg5 = 'Bob,今天天气不错!';
389
+ console.log(`[Alice] >>> ${msg5}`);
390
+ await alice.sendMessage(PORT_BOB, 'Bob', msg5);
391
+ // 等待 Bob 处理
392
+ await new Promise(resolve => setTimeout(resolve, 2000));
393
+ // 汇总结果
394
+ console.log('\n━━━ 步骤 4: 结果汇总 ━━━\n');
395
+ const aliceHistory = alice.getMessageHistory();
396
+ const bobHistory = bob.getMessageHistory();
397
+ console.log(`[Alice] 收到消息: ${aliceHistory.length} 条`);
398
+ console.log(`[Bob] 收到消息: ${bobHistory.length} 条`);
399
+ const harnessCalls = [...aliceHistory, ...bobHistory].filter(m => m.requiresHarness);
400
+ console.log(`\nHarness 调用次数: ${harnessCalls.length}`);
401
+ console.log('\n调用详情:');
402
+ for (const call of harnessCalls) {
403
+ console.log(` - [${call.from}] Gate: ${call.harnessResult?.gate}, Skills: ${call.harnessResult?.skills?.join(', ')}`);
404
+ }
405
+ console.log('\n━━━ 步骤 5: 健康检查 ━━━\n');
406
+ try {
407
+ const aliceHealth = await fetch(`http://localhost:${PORT_ALICE}/health`).then(r => r.json());
408
+ const bobHealth = await fetch(`http://localhost:${PORT_BOB}/health`).then(r => r.json());
409
+ console.log(`[Alice] ${aliceHealth.name} (${aliceHealth.id.substring(0, 8)}...)`);
410
+ console.log(` - 消息数: ${aliceHealth.messageCount}`);
411
+ console.log(` - 邻居: ${aliceHealth.peers.length}`);
412
+ console.log(`[Bob] ${bobHealth.name} (${bobHealth.id.substring(0, 8)}...)`);
413
+ console.log(` - 消息数: ${bobHealth.messageCount}`);
414
+ console.log(` - 邻居: ${bobHealth.peers.length}`);
415
+ }
416
+ catch (err) {
417
+ console.log('健康检查失败:', err);
418
+ }
419
+ // 清理
420
+ console.log('\n━━━ 清理资源 ━━━\n');
421
+ await alice.stop();
422
+ await bob.stop();
423
+ console.log('✓ 测试完成\n');
424
+ console.log('========================================\n');
425
+ // 判断测试是否成功
426
+ const success = harnessCalls.length >= 3;
427
+ if (success) {
428
+ console.log('✅ 测试成功: 智能体成功调用 Harness 进行判断');
429
+ }
430
+ else {
431
+ console.log('⚠️ 测试部分成功: 部分对话触发了 Harness');
432
+ }
433
+ }
434
+ runFullFlowTest().catch(err => {
435
+ console.error('测试失败:', err);
436
+ process.exit(1);
437
+ });
@@ -0,0 +1,143 @@
1
+ /**
2
+ * P2P Agent + Harness Single Flow Test
3
+ * 测试单轮对话流程,验证判断力和 Harness 调用
4
+ *
5
+ * 运行: npx tsx src/test/p2p-agent-harness-single.ts
6
+ */
7
+ import { config } from 'dotenv';
8
+ import express from 'express';
9
+ import { createServer } from 'http';
10
+ import crypto from 'crypto';
11
+ config();
12
+ const PORT_ALICE = 5001;
13
+ const PORT_BOB = 5002;
14
+ // ============================================================================
15
+ // Harness 模块
16
+ // ============================================================================
17
+ class HarnessCore {
18
+ execute(gate, context) {
19
+ const skills = ['arch', 'lead', 'harness-eng'];
20
+ let result = '';
21
+ switch (gate) {
22
+ case 1:
23
+ result = '[架构检查] 分析完成,建议分离关注点';
24
+ break;
25
+ case 2:
26
+ result = '[代码审查] 检查完成,建议添加错误处理';
27
+ break;
28
+ case 5:
29
+ result = '[任务分解] 分解为3个子任务';
30
+ break;
31
+ default: result = `[Gate ${gate}] 处理完成`;
32
+ }
33
+ console.log(` 🔧 Harness 执行: Gate ${gate}, Skills: ${skills.join(', ')}`);
34
+ console.log(` 📋 结果: ${result}`);
35
+ return { result, skills };
36
+ }
37
+ }
38
+ // ============================================================================
39
+ // 智能体
40
+ // ============================================================================
41
+ class Agent {
42
+ id = crypto.randomUUID();
43
+ name;
44
+ port;
45
+ harness = new HarnessCore();
46
+ messages = [];
47
+ constructor(name, port) {
48
+ this.name = name;
49
+ this.port = port;
50
+ }
51
+ async start() {
52
+ const app = express();
53
+ app.use(express.json());
54
+ app.get('/health', (req, res) => {
55
+ res.json({ id: this.id, name: this.name, port: this.port });
56
+ });
57
+ app.get('/discovery', (req, res) => {
58
+ res.json({ id: this.id, name: this.name, port: this.port });
59
+ });
60
+ // 消息处理 - 每个消息只处理一次,不回复
61
+ app.post('/message', async (req, res) => {
62
+ const { fromName, content } = req.body;
63
+ console.log(`\n📨 [${this.name}] 收到来自 ${fromName}: "${content.substring(0, 50)}..."`);
64
+ // 判断是否需要 Harness
65
+ const keywords = ['分析', '架构', '检查', '审核', 'review', '分解', '设计'];
66
+ const needsHarness = keywords.some(k => content.toLowerCase().includes(k));
67
+ if (needsHarness) {
68
+ console.log(`🧠 [${this.name}] 需要调用 Harness`);
69
+ const result = this.harness.execute(1, content);
70
+ console.log(`📤 [${this.name}] 回复: ${result.result}`);
71
+ }
72
+ else {
73
+ console.log(`🧠 [${this.name}] 不需要 Harness`);
74
+ console.log(`📤 [${this.name}] 回复: 收到!`);
75
+ }
76
+ this.messages.push(`[${fromName}]: ${content}`);
77
+ this.messages.push(`[${this.name}]: ${needsHarness ? '已调用Harness' : '简单回复'}`);
78
+ res.json({ ok: true, reply: needsHarness ? '已调用Harness处理' : '收到!' });
79
+ });
80
+ const server = createServer(app);
81
+ return new Promise(resolve => {
82
+ server.listen(this.port, () => {
83
+ console.log(`✓ [${this.name}] 启动 on port ${this.port}`);
84
+ resolve();
85
+ });
86
+ });
87
+ }
88
+ }
89
+ // ============================================================================
90
+ // 测试
91
+ // ============================================================================
92
+ async function runTest() {
93
+ console.log('\n========================================');
94
+ console.log(' P2P Agent + Harness 单轮流程测试');
95
+ console.log('========================================\n');
96
+ const alice = new Agent('Alice', PORT_ALICE);
97
+ const bob = new Agent('Bob', PORT_BOB);
98
+ console.log('━━━ 启动智能体 ━━━\n');
99
+ await alice.start();
100
+ await bob.start();
101
+ console.log('\n━━━ 对话测试 ━━━\n');
102
+ // 对话 1: 需要 Harness
103
+ console.log('【对话 1】Alice -> Bob: 分析架构');
104
+ await fetch(`http://localhost:${PORT_BOB}/message`, {
105
+ method: 'POST',
106
+ headers: { 'Content-Type': 'application/json' },
107
+ body: JSON.stringify({ fromName: 'Alice', content: 'Bob,帮我分析一下代码架构' })
108
+ });
109
+ await new Promise(r => setTimeout(r, 1000));
110
+ // 对话 2: 不需要 Harness
111
+ console.log('\n【对话 2】Alice -> Bob: 简单问候');
112
+ await fetch(`http://localhost:${PORT_BOB}/message`, {
113
+ method: 'POST',
114
+ headers: { 'Content-Type': 'application/json' },
115
+ body: JSON.stringify({ fromName: 'Alice', content: 'Bob,你好吗?' })
116
+ });
117
+ await new Promise(r => setTimeout(r, 1000));
118
+ // 对话 3: 需要 Harness
119
+ console.log('\n【对话 3】Bob -> Alice: 代码审查');
120
+ await fetch(`http://localhost:${PORT_ALICE}/message`, {
121
+ method: 'POST',
122
+ headers: { 'Content-Type': 'application/json' },
123
+ body: JSON.stringify({ fromName: 'Bob', content: 'Alice,帮我 review 这段代码' })
124
+ });
125
+ await new Promise(r => setTimeout(r, 1000));
126
+ console.log('\n━━━ 结果汇总 ━━━\n');
127
+ console.log(`Alice 消息数: ${alice.messages.length}`);
128
+ console.log(`Bob 消息数: ${bob.messages.length}`);
129
+ console.log('\n[Alice] 历史:');
130
+ alice.messages.forEach(m => console.log(` ${m}`));
131
+ console.log('\n[Bob] 历史:');
132
+ bob.messages.forEach(m => console.log(` ${m}`));
133
+ // 健康检查
134
+ const aliceHealth = await fetch(`http://localhost:${PORT_ALICE}/health`).then(r => r.json());
135
+ const bobHealth = await fetch(`http://localhost:${PORT_BOB}/health`).then(r => r.json());
136
+ console.log('\n━━━ 健康状态 ━━━');
137
+ console.log(`Alice: ${aliceHealth.name} (ID: ${aliceHealth.id.substring(0, 8)}...)`);
138
+ console.log(`Bob: ${bobHealth.name} (ID: ${bobHealth.id.substring(0, 8)}...)`);
139
+ console.log('\n========================================');
140
+ console.log(' 测试完成');
141
+ console.log('========================================\n');
142
+ }
143
+ runTest().catch(console.error);