@bolloon/bolloon-agent 0.2.8 → 0.2.10

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 -157
  223. package/scripts/build-cli.js +216 -0
  224. package/scripts/build-web.ts +125 -0
  225. package/scripts/postinstall.js +153 -0
  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,219 @@
1
+ import { describe, it, expect, beforeEach, vi } from 'vitest';
2
+ import { evaluateDecision, submitDecisionResponse, queryInternalAgents, getPendingDecisions, getDecisionRequest, getDecisionStats, setConfidenceThreshold, setDefaultDecisionLevel, } from '../pi-ecosystem-judgment/decision.js';
3
+ import * as judgmentModule from '../pi-ecosystem-judgment/index.js';
4
+ vi.mock('../pi-ecosystem-colony/index.js', () => ({
5
+ listAnts: vi.fn().mockReturnValue([
6
+ { id: 'ant-1', name: 'BuilderAnt', signal: 'ACTIVE', capabilities: ['coding'] },
7
+ { id: 'ant-2', name: 'ReviewerAnt', signal: 'ACTIVE', capabilities: ['review'] },
8
+ { id: 'ant-3', name: 'TesterAnt', signal: 'ACTIVE', capabilities: ['testing'] },
9
+ ]),
10
+ }));
11
+ vi.mock('../pi-ecosystem-subagents/index.js', () => ({
12
+ listSubagents: vi.fn().mockReturnValue([
13
+ { id: 'sub-1', name: 'CodeSubagent', status: 'running', capabilities: ['coding'] },
14
+ { id: 'sub-2', name: 'DocSubagent', status: 'running', capabilities: ['writing'] },
15
+ ]),
16
+ }));
17
+ describe('Decision System - Internal vs External Judgment Communication', () => {
18
+ beforeEach(() => {
19
+ setConfidenceThreshold(0.7);
20
+ setDefaultDecisionLevel('autonomous');
21
+ vi.clearAllMocks();
22
+ });
23
+ describe('Decision Level Determination', () => {
24
+ it('should be autonomous when confidence >= threshold', async () => {
25
+ vi.spyOn(judgmentModule, 'calculateConfidence').mockReturnValueOnce(0.9);
26
+ const request = await evaluateDecision('Use const instead of var', 'typescript', 'agent-001', 0.7);
27
+ expect(request.level).toBe('autonomous');
28
+ expect(request.targets).toEqual([]);
29
+ expect(request.status).toBe('pending');
30
+ });
31
+ it('should consult_internal when confidence >= threshold * 0.7 but < threshold', async () => {
32
+ vi.spyOn(judgmentModule, 'calculateConfidence').mockReturnValueOnce(0.5);
33
+ const request = await evaluateDecision('Refactor this function', 'refactor', 'agent-001', 0.7);
34
+ expect(request.level).toBe('consult_internal');
35
+ expect(request.targets).toContain('colony_ant');
36
+ expect(request.targets).toContain('subagent');
37
+ expect(request.targets).not.toContain('p2p_agent');
38
+ expect(request.targets).not.toContain('human');
39
+ });
40
+ it('should consult_external when confidence >= threshold * 0.4 but < threshold * 0.7', async () => {
41
+ vi.spyOn(judgmentModule, 'calculateConfidence').mockReturnValueOnce(0.35);
42
+ const request = await evaluateDecision('Cross-system migration strategy', 'migration', 'agent-001', 0.7);
43
+ expect(request.level).toBe('consult_external');
44
+ expect(request.targets).toContain('p2p_agent');
45
+ expect(request.targets).toContain('colony_ant');
46
+ expect(request.targets).toContain('subagent');
47
+ });
48
+ it('should require_human when confidence < threshold * 0.4', async () => {
49
+ vi.spyOn(judgmentModule, 'calculateConfidence').mockReturnValueOnce(0.2);
50
+ const request = await evaluateDecision('Strategic pivot decision', 'strategy', 'agent-001', 0.7);
51
+ expect(request.level).toBe('require_human');
52
+ expect(request.targets).toEqual(['human']);
53
+ });
54
+ it('should default to confidence 0.5 when no judgments exist', async () => {
55
+ vi.spyOn(judgmentModule, 'calculateConfidence').mockReturnValueOnce(0.5);
56
+ const request = await evaluateDecision('No prior judgment context', 'unknown', 'agent-001', 0.7);
57
+ expect(request.confidence).toBe(0.5);
58
+ expect(request.level).toBe('consult_internal');
59
+ expect(request.targets).toContain('colony_ant');
60
+ });
61
+ });
62
+ describe('Internal Consultation (colony_ant, subagent)', () => {
63
+ it('should query up to 3 colony ants for consult_internal', async () => {
64
+ const request = await evaluateDecision('Which approach is better: A or B?', 'decision', 'agent-001', 0.7);
65
+ request.level = 'consult_internal';
66
+ request.targets = ['colony_ant', 'subagent'];
67
+ const results = await queryInternalAgents(request);
68
+ expect(results.length).toBeGreaterThan(0);
69
+ expect(results.some(r => r.target === 'colony_ant')).toBe(true);
70
+ });
71
+ it('should query up to 2 subagents for consult_internal', async () => {
72
+ const request = await evaluateDecision('Code review decision', 'review', 'agent-001', 0.7);
73
+ request.level = 'consult_internal';
74
+ request.targets = ['colony_ant', 'subagent'];
75
+ const results = await queryInternalAgents(request);
76
+ expect(results.some(r => r.target === 'subagent')).toBe(true);
77
+ });
78
+ it('should include consultation results in request', async () => {
79
+ vi.spyOn(judgmentModule, 'calculateConfidence').mockReturnValueOnce(0.5);
80
+ const request = await evaluateDecision('Implementation strategy', 'strategy', 'agent-001', 0.7);
81
+ expect(request.targets.length).toBeGreaterThan(0);
82
+ });
83
+ });
84
+ describe('External Consultation (p2p_agent)', () => {
85
+ it('should include p2p_agent in consult_external targets', async () => {
86
+ vi.spyOn(judgmentModule, 'calculateConfidence').mockReturnValueOnce(0.35);
87
+ const request = await evaluateDecision('Peer system integration decision', 'integration', 'agent-001', 0.7);
88
+ expect(request.level).toBe('consult_external');
89
+ expect(request.targets).toContain('p2p_agent');
90
+ });
91
+ it('should support external peer-to-peer consultation', async () => {
92
+ vi.spyOn(judgmentModule, 'calculateConfidence').mockReturnValueOnce(0.35);
93
+ const request = await evaluateDecision('Protocol version negotiation', 'protocol', 'agent-001', 0.7);
94
+ expect(request.targets).toContain('p2p_agent');
95
+ expect(request.targets).toContain('colony_ant');
96
+ expect(request.targets).toContain('subagent');
97
+ });
98
+ });
99
+ describe('Decision Response Flow', () => {
100
+ it('should update status to authorized on positive response', async () => {
101
+ const request = await evaluateDecision('Proceed with deployment', 'deploy', 'agent-001', 0.7);
102
+ const response = await submitDecisionResponse(request.id, {
103
+ authorized: true,
104
+ content: 'Approved',
105
+ by: 'human',
106
+ timestamp: new Date().toISOString(),
107
+ });
108
+ expect(response?.status).toBe('authorized');
109
+ expect(response?.respondedAt).toBeDefined();
110
+ });
111
+ it('should update status to rejected on negative response', async () => {
112
+ const request = await evaluateDecision('Skip tests for faster delivery', 'testing', 'agent-001', 0.7);
113
+ const response = await submitDecisionResponse(request.id, {
114
+ authorized: false,
115
+ content: 'No, tests are required',
116
+ by: 'human',
117
+ timestamp: new Date().toISOString(),
118
+ });
119
+ expect(response?.status).toBe('rejected');
120
+ });
121
+ it('should support delegation to other targets', async () => {
122
+ const request = await evaluateDecision('Architecture decision', 'architecture', 'agent-001', 0.7);
123
+ const response = await submitDecisionResponse(request.id, {
124
+ authorized: true,
125
+ content: 'Delegating to senior architect',
126
+ delegate: 'colony_ant',
127
+ by: 'human',
128
+ timestamp: new Date().toISOString(),
129
+ });
130
+ expect(response?.response?.delegate).toBe('colony_ant');
131
+ });
132
+ });
133
+ describe('Decision State Tracking', () => {
134
+ it('should track pending decisions', async () => {
135
+ await evaluateDecision('Decision 1', 'context', 'agent-001', 0.7);
136
+ await evaluateDecision('Decision 2', 'context', 'agent-001', 0.7);
137
+ const pending = getPendingDecisions();
138
+ expect(pending.length).toBeGreaterThanOrEqual(2);
139
+ });
140
+ it('should retrieve decision by ID', async () => {
141
+ const created = await evaluateDecision('Test Decision', 'context', 'agent-001', 0.7);
142
+ const retrieved = getDecisionRequest(created.id);
143
+ expect(retrieved).toBeDefined();
144
+ expect(retrieved?.description).toBe('Test Decision');
145
+ });
146
+ it('should calculate decision statistics', async () => {
147
+ await evaluateDecision('Decision A', 'context', 'agent-001', 0.7);
148
+ await evaluateDecision('Decision B', 'context', 'agent-001', 0.7);
149
+ const stats = getDecisionStats();
150
+ expect(stats.total).toBeGreaterThanOrEqual(2);
151
+ expect(stats.pending).toBeGreaterThanOrEqual(2);
152
+ });
153
+ });
154
+ describe('Threshold Sensitivity', () => {
155
+ it('should escalate to require_human with very high threshold', async () => {
156
+ setConfidenceThreshold(0.9);
157
+ vi.spyOn(judgmentModule, 'calculateConfidence').mockReturnValueOnce(0.3);
158
+ const request = await evaluateDecision('Conservative decision', 'context', 'agent-001');
159
+ expect(request.level).toBe('require_human');
160
+ expect(request.targets).toEqual(['human']);
161
+ });
162
+ it('should be autonomous with low threshold', async () => {
163
+ setConfidenceThreshold(0.3);
164
+ vi.spyOn(judgmentModule, 'calculateConfidence').mockReturnValueOnce(0.5);
165
+ const request = await evaluateDecision('Aggressive decision', 'context', 'agent-001');
166
+ expect(request.level).toBe('autonomous');
167
+ expect(request.targets).toEqual([]);
168
+ });
169
+ });
170
+ describe('Cross-Cutting Concerns', () => {
171
+ it('should create unique decision IDs', async () => {
172
+ const request1 = await evaluateDecision('Decision 1', 'c', 'a', 0.7);
173
+ const request2 = await evaluateDecision('Decision 2', 'c', 'a', 0.7);
174
+ expect(request1.id).not.toBe(request2.id);
175
+ });
176
+ it('should include agent ID in request', async () => {
177
+ const request = await evaluateDecision('Test', 'c', 'my-agent-123', 0.7);
178
+ expect(request.agentId).toBe('my-agent-123');
179
+ });
180
+ it('should record creation timestamp', async () => {
181
+ const before = new Date().toISOString();
182
+ const request = await evaluateDecision('Test', 'c', 'a', 0.7);
183
+ const after = new Date().toISOString();
184
+ expect(request.createdAt).toBeDefined();
185
+ expect(request.createdAt >= before).toBe(true);
186
+ expect(request.createdAt <= after).toBe(true);
187
+ });
188
+ });
189
+ });
190
+ describe('Decision Level Boundary Conditions', () => {
191
+ beforeEach(() => {
192
+ setConfidenceThreshold(0.7);
193
+ });
194
+ it.each([
195
+ { confidence: 0.9, expectedLevel: 'autonomous' },
196
+ { confidence: 0.5, expectedLevel: 'consult_internal' },
197
+ { confidence: 0.35, expectedLevel: 'consult_external' },
198
+ { confidence: 0.2, expectedLevel: 'require_human' },
199
+ ])('confidence $confidence should map to $expectedLevel', async ({ confidence, expectedLevel }) => {
200
+ vi.spyOn(judgmentModule, 'calculateConfidence').mockReturnValueOnce(confidence);
201
+ const request = await evaluateDecision('Boundary test', 'boundary', 'agent-001', 0.7);
202
+ expect(request.level).toBe(expectedLevel);
203
+ });
204
+ });
205
+ describe('Consultation Target Matrix', () => {
206
+ beforeEach(() => {
207
+ setConfidenceThreshold(0.7);
208
+ });
209
+ const matrix = [
210
+ { level: 'autonomous', expectedTargets: [] },
211
+ { level: 'consult_internal', expectedTargets: ['colony_ant', 'subagent'] },
212
+ { level: 'consult_external', expectedTargets: ['colony_ant', 'subagent', 'p2p_agent'] },
213
+ { level: 'require_human', expectedTargets: ['human'] },
214
+ ];
215
+ it.each(matrix)('level $level should have targets $expectedTargets', ({ level, expectedTargets }) => {
216
+ expect(level).toBeDefined();
217
+ expect(expectedTargets).toBeDefined();
218
+ });
219
+ });
@@ -0,0 +1,220 @@
1
+ /**
2
+ * LLM-as-Judge 集成测试
3
+ *
4
+ * 测试内容:
5
+ * 1. LLMJudgmentClient 的 LLM 调用
6
+ * 2. Prompt 变体 (concise/standard/deep) 的选择
7
+ * 3. Skill Prompt 配置化
8
+ * 4. ChannelJudgmentEngine 的 LLM 集成
9
+ *
10
+ * 运行: npx tsx src/test/llm-judgment-integration.test.ts
11
+ */
12
+ import { config } from 'dotenv';
13
+ import * as path from 'path';
14
+ import { fileURLToPath } from 'url';
15
+ import { createLLMJudgmentClient, JUDGMENT_PROMPTS } from '../llm/llm-judgment-client.js';
16
+ import { createChannelJudgmentEngine } from '../bollharness-integration/channel-judgment-engine.js';
17
+ import { createLLMJudgmentEngine, SKILL_PROMPTS } from '../bollharness-integration/llm-judgment-engine.js';
18
+ import * as fs from 'fs';
19
+ config();
20
+ const __filename = fileURLToPath(import.meta.url);
21
+ const __dirname = path.dirname(__filename);
22
+ // 测试用例
23
+ const TEST_CASES = [
24
+ {
25
+ input: '我们需要设计一个用户认证系统,包含登录、注册和OAuth社交登录。',
26
+ description: '架构设计问题',
27
+ expected: { approach: 'design', complexity: 'complex' }
28
+ },
29
+ {
30
+ input: '帮我 review 一下这段代码有没有安全问题',
31
+ description: '代码审查问题',
32
+ expected: { approach: 'analyze', skills: ['guardian-fixer'] }
33
+ },
34
+ {
35
+ input: '如何实现JWT token的刷新机制?',
36
+ description: '实现问题',
37
+ expected: { approach: 'implement' }
38
+ },
39
+ {
40
+ input: '这个任务比较复杂,帮我分解一下',
41
+ description: '任务分解问题',
42
+ expected: { approach: 'coordinate', skills: ['task-arch'] }
43
+ }
44
+ ];
45
+ // 测试 Prompt 变体
46
+ async function testPromptVariants() {
47
+ console.log('\n━━━ Prompt 变体测试 ━━━\n');
48
+ const client = await createLLMJudgmentClient({ useLLM: true });
49
+ for (const promptName of ['default', 'architecture', 'code', 'security']) {
50
+ const config = JUDGMENT_PROMPTS[promptName];
51
+ console.log(`[${promptName}]`);
52
+ console.log(` System prompt 长度: ${config.systemPrompt.length} 字符`);
53
+ console.log(` Output format: ${config.outputFormat}`);
54
+ }
55
+ }
56
+ // 测试 LLMJudgmentClient
57
+ async function testLLMJudgmentClient() {
58
+ console.log('\n━━━ LLMJudgmentClient 测试 ━━━\n');
59
+ const client = await createLLMJudgmentClient({ useLLM: false }); // 快速模式
60
+ for (const tc of TEST_CASES) {
61
+ console.log(`测试: ${tc.description}`);
62
+ console.log(`输入: "${tc.input.substring(0, 40)}..."`);
63
+ const result = await client.judge(tc.input, {
64
+ senderName: 'TestUser',
65
+ history: ['之前的对话']
66
+ });
67
+ console.log(` Approach: ${result.decision.approach}`);
68
+ console.log(` Complexity: ${result.assessment.complexity}`);
69
+ console.log(` Skills: ${result.routing.skills.join(', ')}`);
70
+ console.log();
71
+ }
72
+ }
73
+ // 测试 Skill Prompts 配置
74
+ function testSkillPromptsConfig() {
75
+ console.log('\n━━━ Skill Prompts 配置化测试 ━━━\n');
76
+ const skillNames = Object.keys(SKILL_PROMPTS);
77
+ console.log(`已配置的 Skills: ${skillNames.join(', ')}\n`);
78
+ for (const [name, skill] of Object.entries(SKILL_PROMPTS)) {
79
+ console.log(`[${name}]`);
80
+ console.log(` 名称: ${skill.name}`);
81
+ console.log(` 描述: ${skill.description}`);
82
+ console.log(` System prompt 长度: ${skill.systemPrompt.length} 字符`);
83
+ console.log(` Output format: ${skill.outputFormat}`);
84
+ console.log();
85
+ }
86
+ }
87
+ // 测试 YAML 配置加载
88
+ async function testYAMLConfig() {
89
+ console.log('\n━━━ YAML 配置文件测试 ━━━\n');
90
+ const yamlPath = path.join(__dirname, '../bollharness-integration/judgment-prompts.yaml');
91
+ try {
92
+ const content = fs.readFileSync(yamlPath, 'utf-8');
93
+ console.log(`✓ YAML 配置文件存在`);
94
+ console.log(` 路径: ${yamlPath}`);
95
+ console.log(` 大小: ${content.length} 字节`);
96
+ // 简单解析检查
97
+ const hasPromptVariants = content.includes('prompt_variants');
98
+ const hasSkills = content.includes('skills:');
99
+ const hasOutputFormats = content.includes('output_formats');
100
+ console.log(` 包含 Prompt 变体: ${hasPromptVariants ? '✓' : '✗'}`);
101
+ console.log(` 包含 Skills 配置: ${hasSkills ? '✓' : '✗'}`);
102
+ console.log(` 包含输出格式: ${hasOutputFormats ? '✓' : '✗'}`);
103
+ // 解析行数统计
104
+ const lines = content.split('\n').filter(l => l.trim() && !l.trim().startsWith('#'));
105
+ console.log(` 非注释行数: ${lines.length}`);
106
+ }
107
+ catch (err) {
108
+ console.error(`✗ YAML 配置文件读取失败:`, err);
109
+ }
110
+ }
111
+ // 测试 ChannelJudgmentEngine
112
+ async function testChannelJudgmentEngine() {
113
+ console.log('\n━━━ ChannelJudgmentEngine 测试 ━━━\n');
114
+ const engine = createChannelJudgmentEngine({ useLLM: false });
115
+ const testInputs = [
116
+ '我们需要设计一个微服务架构',
117
+ '帮我 review 这段代码',
118
+ '这个功能需要安全检查',
119
+ '任务分解一下',
120
+ '实现登录功能'
121
+ ];
122
+ for (const input of testInputs) {
123
+ const result = await engine.decide({
124
+ conversationHistory: [],
125
+ currentMessage: input,
126
+ senderName: 'TestUser'
127
+ });
128
+ console.log(`输入: "${input}"`);
129
+ console.log(` 调用 Harness: ${result.shouldCall}`);
130
+ if (result.shouldCall) {
131
+ console.log(` Gate: ${result.gate}`);
132
+ console.log(` Skills: ${result.skills.join(', ')}`);
133
+ console.log(` 置信度: ${(result.confidence * 100).toFixed(0)}%`);
134
+ }
135
+ console.log();
136
+ }
137
+ }
138
+ // 测试 LLMJudgmentEngine
139
+ async function testLLMJudgmentEngine() {
140
+ console.log('\n━━━ LLMJudgmentEngine 测试 ━━━\n');
141
+ const engine = createLLMJudgmentEngine({ useLLM: false });
142
+ for (const tc of TEST_CASES) {
143
+ console.log(`测试: ${tc.description}`);
144
+ const result = await engine.judge(tc.input, { history: ['之前的对话'] });
145
+ console.log(` Understanding:`);
146
+ console.log(` - Essence: ${result.understanding.essence}`);
147
+ console.log(` - Core Need: ${result.understanding.coreNeed}`);
148
+ console.log(` Assessment:`);
149
+ console.log(` - Complexity: ${result.assessment.complexity}`);
150
+ console.log(` - Depth: ${result.assessment.depth}`);
151
+ console.log(` Decision:`);
152
+ console.log(` - Approach: ${result.decision.approach}`);
153
+ console.log(` Routing:`);
154
+ console.log(` - Skills: ${result.routing.skills.join(', ')}`);
155
+ console.log(` - Collaboration: ${result.routing.collaboration}`);
156
+ console.log();
157
+ }
158
+ }
159
+ // 测试 DynamicSkillRouter
160
+ async function testDynamicSkillRouter() {
161
+ console.log('\n━━━ DynamicSkillRouter 测试 ━━━\n');
162
+ const { createDynamicSkillRouter } = await import('../bollharness-integration/llm-judgment-engine.js');
163
+ const router = createDynamicSkillRouter({ useLLM: false });
164
+ const availableSkills = router.listSkills();
165
+ console.log(`可用的 Skills: ${availableSkills.join(', ')}`);
166
+ // 测试单个 Skill 调用
167
+ const judgment = {
168
+ understanding: {
169
+ essence: 'how-to',
170
+ coreNeed: '设计方案',
171
+ implicit: []
172
+ },
173
+ assessment: {
174
+ complexity: 'complex',
175
+ complexityReason: '涉及架构设计',
176
+ depth: 'deeper',
177
+ urgency: 'medium'
178
+ },
179
+ decision: {
180
+ approach: 'design',
181
+ reasoning: '需要架构设计'
182
+ },
183
+ routing: {
184
+ skills: ['arch'],
185
+ agents: [],
186
+ collaboration: 'pair'
187
+ },
188
+ artifacts: {
189
+ required: ['架构文档']
190
+ }
191
+ };
192
+ const results = await router.routeAndExecute('设计一个电商系统', judgment);
193
+ console.log(`\nSkill 执行结果:`);
194
+ for (const [skill, result] of Object.entries(results)) {
195
+ console.log(` ${skill}: ${String(result).substring(0, 100)}...`);
196
+ }
197
+ }
198
+ // 主测试函数
199
+ async function main() {
200
+ console.log('========================================');
201
+ console.log(' LLM-as-Judge 集成测试');
202
+ console.log('========================================');
203
+ try {
204
+ await testPromptVariants();
205
+ await testLLMJudgmentClient();
206
+ testSkillPromptsConfig();
207
+ await testYAMLConfig();
208
+ await testChannelJudgmentEngine();
209
+ await testLLMJudgmentEngine();
210
+ await testDynamicSkillRouter();
211
+ console.log('\n========================================');
212
+ console.log(' 测试完成 ✓');
213
+ console.log('========================================\n');
214
+ }
215
+ catch (err) {
216
+ console.error('\n测试失败:', err);
217
+ process.exit(1);
218
+ }
219
+ }
220
+ main();