@bolloon/bolloon-agent 0.3.52 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +135 -135
- package/bin/bolloon-cli.cjs +183 -183
- package/bin/bolloon.cjs +0 -0
- package/bin/bolloon.js +157 -0
- package/dist/agents/constraint-layer.js +19 -19
- package/dist/agents/judgment-protocol.js +14 -14
- package/dist/agents/loop-review.js +21 -0
- package/dist/agents/pi-sdk-tools.js +86 -2
- package/dist/agents/pi-sdk-types.js +12 -12
- package/dist/agents/pi-sdk.js +90 -90
- package/dist/agents/shell-guard.js +22 -1
- package/dist/agents/skill-organizer.js +19 -19
- package/dist/agents/verify-recipe.js +84 -0
- package/dist/agents/workflow-pivot-loop.js +101 -13
- package/dist/bollharness/src/scripts/deploy-guard.js +8 -8
- package/dist/bollharness-integration/context-router-judgment.js +4 -4
- package/dist/bollharness-integration/context-router.js +292 -292
- package/dist/bollharness-integration/gate-state-machine.js +13 -13
- package/dist/bollharness-integration/llm-judgment-engine.js +134 -134
- package/dist/bollharness-integration/skill-adapter.js +21 -21
- package/dist/bootstrap/chat-archiver.js +14 -14
- package/dist/bootstrap/context-os.js +50 -40
- package/dist/bootstrap/memory-compressor.js +13 -13
- package/dist/cli-entry.js +36 -36
- package/dist/context-compaction/auto-compact.js +7 -7
- package/dist/electron/first-run.js +54 -54
- package/dist/electron-build/electron/first-run.js +54 -54
- package/dist/electron-preload.js.map +1 -1
- package/dist/electron.js.map +1 -1
- package/dist/external-engines/delegate-handle.js +70 -0
- package/dist/external-engines/delegate.js +24 -3
- package/dist/index.js +112 -112
- package/dist/llm/error-lessons.js +53 -0
- package/dist/llm/llm-judgment-client.js +102 -102
- package/dist/llm/pi-ai.js +61 -48
- package/dist/llm/system-prompt/layers/channel/human-async.md +41 -41
- package/dist/llm/system-prompt/layers/channel/local.md +14 -14
- package/dist/llm/system-prompt/layers/channel/p2p-agent.md +18 -18
- package/dist/llm/system-prompt/layers/channel/p2p-peer-sync.md +51 -51
- package/dist/llm/system-prompt/layers/channel/p2p-proactive.md +43 -43
- package/dist/llm/system-prompt/layers/channel/p2p-visitor.md +19 -19
- package/dist/llm/system-prompt/layers/channel/session-handoff.md +61 -61
- package/dist/llm/system-prompt/layers/core/artifacts_storage.md +89 -89
- package/dist/llm/system-prompt/layers/core/evenhandedness.md +21 -21
- package/dist/llm/system-prompt/layers/core/external-engagement.md +73 -73
- package/dist/llm/system-prompt/layers/core/hibs_reminders.md +15 -15
- package/dist/llm/system-prompt/layers/core/identity.md +48 -48
- package/dist/llm/system-prompt/layers/core/knowledge.md +17 -17
- package/dist/llm/system-prompt/layers/core/memory_system.md +12 -12
- package/dist/llm/system-prompt/layers/core/network_filesystem.md +28 -28
- package/dist/llm/system-prompt/layers/core/refusal.md +37 -37
- package/dist/llm/system-prompt/layers/core/tone.md +31 -31
- package/dist/llm/system-prompt/layers/core/tools.thin.md +13 -13
- package/dist/llm/system-prompt/layers/core/wellbeing.md +41 -41
- package/dist/llm/system-prompt/layers/role/architect.md +20 -20
- package/dist/llm/system-prompt/layers/role/expert.md +19 -19
- package/dist/llm/system-prompt/layers/role/implementer.md +15 -15
- package/dist/llm/system-prompt/layers/role/security.md +15 -15
- package/dist/llm/system-prompt/layers/tool/artifacts.md +72 -72
- package/dist/llm/system-prompt/layers/tool/bash.md +25 -25
- package/dist/llm/system-prompt/layers/tool/goal_handoff.md +77 -77
- package/dist/llm/system-prompt/layers/tool/hibs_api.md +171 -171
- package/dist/llm/system-prompt/layers/tool/image_search.md +70 -70
- package/dist/llm/system-prompt/layers/tool/manifest.md +89 -89
- package/dist/llm/system-prompt/layers/tool/mcp_apps.md +53 -53
- package/dist/llm/system-prompt/layers/tool/p2p_request.md +61 -61
- package/dist/llm/system-prompt/layers/tool/web_search.md +83 -83
- package/dist/llm/system-prompt/registry.js +9 -1
- package/dist/llm/tool-manifest/ask_user_input.js +1 -1
- package/dist/llm/tool-manifest/bash.js +3 -3
- package/dist/llm/tool-manifest/create_file.js +4 -4
- package/dist/llm/tool-manifest/fetch_sports_data.js +3 -3
- package/dist/llm/tool-manifest/image_search.js +2 -2
- package/dist/llm/tool-manifest/index.js +0 -59
- package/dist/llm/tool-manifest/mcp.js +2 -2
- package/dist/llm/tool-manifest/message_compose.js +3 -3
- package/dist/llm/tool-manifest/places.js +2 -2
- package/dist/llm/tool-manifest/present_files.js +1 -1
- package/dist/llm/tool-manifest/recipe.js +2 -2
- package/dist/llm/tool-manifest/str_replace.js +5 -5
- package/dist/llm/tool-manifest/view.js +3 -3
- package/dist/llm/tool-manifest/weather.js +4 -4
- package/dist/llm/tool-manifest/web.js +4 -4
- package/dist/locales/en.js +28 -0
- package/dist/locales/zh.js +26 -0
- package/dist/pi-ecosystem-colony/index.js +365 -0
- package/dist/pi-ecosystem-judgment/causal-judge.js +51 -51
- package/dist/pi-ecosystem-judgment/distill-prompt.js +42 -42
- package/dist/pi-ecosystem-judgment/distillation.js +14 -14
- package/dist/pi-ecosystem-judgment/monitor-gate.js +28 -28
- package/dist/pi-ecosystem-judgment/value-injection.js +102 -102
- package/dist/security/context-router-tool.js +15 -15
- package/dist/social/ant-colony/AdaptiveHeartbeat.js +101 -0
- package/dist/social/ant-colony/PheromoneEngine.js +227 -0
- package/dist/social/ant-colony/index.js +6 -0
- package/dist/social/ant-colony/types.js +24 -0
- package/dist/storage/trajectory.js +101 -0
- package/dist/test/ai-judgment-test.js +80 -0
- package/dist/test/bollharness-integration.test.js +318 -0
- package/dist/test/channel-agent-multi-dialogue.js +205 -0
- package/dist/test/channel-heartbeat-agent-test.js +201 -0
- package/dist/test/constraint-layer.test.js +164 -0
- package/dist/test/diap-identity-test.js +172 -0
- package/dist/test/diap-quick-test.js +62 -0
- package/dist/test/global-shared-context.test.js +315 -0
- package/dist/test/harness-judgment-injection.test.js +246 -0
- package/dist/test/harness-workflow-integrator-test.js +228 -0
- package/dist/test/human-value-store.test.js +243 -0
- package/dist/test/hybrid-integration-test.js +118 -0
- package/dist/test/hybrid-messenger-verify.js +55 -0
- package/dist/test/iroh-bistream-debug.js +38 -0
- package/dist/test/iroh-communication.test.js +66 -0
- package/dist/test/iroh-debug-test.js +57 -0
- package/dist/test/iroh-diap-test.js +71 -0
- package/dist/test/iroh-direct-connect.js +55 -0
- package/dist/test/iroh-e2e-fixed.js +89 -0
- package/dist/test/iroh-e2e-same-process.js +63 -0
- package/dist/test/iroh-e2e.js +66 -0
- package/dist/test/iroh-final-e2e.js +72 -0
- package/dist/test/iroh-relay-test.js +37 -0
- package/dist/test/iroh-simple-test.js +41 -0
- package/dist/test/iroh-transport-verify.js +54 -0
- package/dist/test/iroh-transport.test.js +37 -0
- package/dist/test/iroh-two-nodes.js +70 -0
- package/dist/test/iroh-verify.js +44 -0
- package/dist/test/judgment-decision.test.js +219 -0
- package/dist/test/llm-judgment-integration.test.js +220 -0
- package/dist/test/p2p-agent-complex-dialogue.js +385 -0
- package/dist/test/p2p-agent-dialogue.js +341 -0
- package/dist/test/p2p-agent-full-bidirectional.js +510 -0
- package/dist/test/p2p-agent-harness-flow.js +437 -0
- package/dist/test/p2p-agent-harness-single.js +143 -0
- package/dist/test/p2p-ai-dialogue-test.js +318 -0
- package/dist/test/p2p-cid-connect-test.js +195 -0
- package/dist/test/p2p-connect-receiver.js +69 -0
- package/dist/test/p2p-doc-transfer.js +110 -0
- package/dist/test/p2p-identity-page-test.js +77 -0
- package/dist/test/p2p-iroh-test.js +171 -0
- package/dist/test/p2p-minimal-test.js +241 -0
- package/dist/test/p2p-node-1.js +148 -0
- package/dist/test/p2p-node-2.js +148 -0
- package/dist/test/p2p-server.js +281 -0
- package/dist/test/p2p-two-nodes-test.js +438 -0
- package/dist/test/pi-sdk.test.js +44 -0
- package/dist/test/set-persona.js +40 -0
- package/dist/test/simple.test.js +9 -0
- package/dist/test/storage-integration.test.js +150 -0
- package/dist/test/subagent-manager.test.js +276 -0
- package/dist/test/test-gate-flow.test.js +81 -0
- package/dist/test/workflow-engine.test.js +87 -0
- package/dist/test/workflow-pivot-loop.test.js +246 -0
- package/dist/web/api-config.html +779 -779
- package/dist/web/client-hearth.js +10 -10
- package/dist/web/components/wallet-viem.mjs +118 -118
- package/dist/web/delivery-ledger.js +103 -0
- package/dist/web/i18n.js +104 -0
- package/dist/web/index.html +472 -472
- package/dist/web/manifest.json +20 -20
- package/dist/web/routes-tasks.js +242 -24
- package/dist/web/server-storage.js +111 -0
- package/dist/web/server.js +55 -26
- package/dist/web/style.css +4946 -4946
- package/dist/web/task-breaker.js +18 -0
- package/dist/web/task-cancel.js +35 -0
- package/dist/web/task-deps.js +36 -0
- package/dist/web/task-review.js +27 -0
- package/dist/web/task-verify.js +60 -0
- package/package.json +196 -196
- package/scripts/build-cli.js +215 -215
- package/scripts/build-web.ts +130 -130
- package/scripts/postinstall.js +152 -152
- package/bin/bolloon-daemon.sh +0 -207
- package/dist/constraint-runtime/reference_data/archive_surface_snapshot.json +0 -63
- package/dist/constraint-runtime/reference_data/commands_snapshot.json +0 -1037
- package/dist/constraint-runtime/reference_data/subsystems/assistant.json +0 -8
- package/dist/constraint-runtime/reference_data/subsystems/bootstrap.json +0 -8
- package/dist/constraint-runtime/reference_data/subsystems/bridge.json +0 -32
- package/dist/constraint-runtime/reference_data/subsystems/buddy.json +0 -13
- package/dist/constraint-runtime/reference_data/subsystems/cli.json +0 -26
- package/dist/constraint-runtime/reference_data/subsystems/components.json +0 -32
- package/dist/constraint-runtime/reference_data/subsystems/constants.json +0 -28
- package/dist/constraint-runtime/reference_data/subsystems/coordinator.json +0 -8
- package/dist/constraint-runtime/reference_data/subsystems/entrypoints.json +0 -15
- package/dist/constraint-runtime/reference_data/subsystems/hooks.json +0 -32
- package/dist/constraint-runtime/reference_data/subsystems/keybindings.json +0 -21
- package/dist/constraint-runtime/reference_data/subsystems/memdir.json +0 -15
- package/dist/constraint-runtime/reference_data/subsystems/migrations.json +0 -18
- package/dist/constraint-runtime/reference_data/subsystems/moreright.json +0 -8
- package/dist/constraint-runtime/reference_data/subsystems/native_ts.json +0 -11
- package/dist/constraint-runtime/reference_data/subsystems/outputStyles.json +0 -8
- package/dist/constraint-runtime/reference_data/subsystems/plugins.json +0 -9
- package/dist/constraint-runtime/reference_data/subsystems/remote.json +0 -11
- package/dist/constraint-runtime/reference_data/subsystems/schemas.json +0 -8
- package/dist/constraint-runtime/reference_data/subsystems/screens.json +0 -10
- package/dist/constraint-runtime/reference_data/subsystems/server.json +0 -10
- package/dist/constraint-runtime/reference_data/subsystems/services.json +0 -32
- package/dist/constraint-runtime/reference_data/subsystems/skills.json +0 -27
- package/dist/constraint-runtime/reference_data/subsystems/state.json +0 -13
- package/dist/constraint-runtime/reference_data/subsystems/types.json +0 -18
- package/dist/constraint-runtime/reference_data/subsystems/upstreamproxy.json +0 -9
- package/dist/constraint-runtime/reference_data/subsystems/utils.json +0 -32
- package/dist/constraint-runtime/reference_data/subsystems/vim.json +0 -12
- package/dist/constraint-runtime/reference_data/subsystems/voice.json +0 -8
- package/dist/constraint-runtime/reference_data/tools_snapshot.json +0 -922
- package/dist/electron/config.js.map +0 -1
- package/dist/electron/dialogs.js.map +0 -1
- package/dist/electron/first-run.js.map +0 -1
- package/dist/electron/ipc.js.map +0 -1
- package/dist/electron/logger.js.map +0 -1
- package/dist/electron/main.js.map +0 -1
- package/dist/electron/menu.js.map +0 -1
- package/dist/electron/paths.js.map +0 -1
- package/dist/electron/server.js.map +0 -1
- package/dist/electron/tray.js.map +0 -1
- package/dist/electron/window.js.map +0 -1
- package/dist/utils/auto-update.js.map +0 -1
- package/dist/web/client.js.map +0 -7
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
2
|
+
import * as fs from 'fs/promises';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import { GlobalSharedContextManager, resetGlobalSharedContext } from '../social/global-shared-context.js';
|
|
5
|
+
const TEST_CONTEXT_PATH = path.join('/tmp', '.bolloon-test', 'sessions', 'test-global-context.json');
|
|
6
|
+
describe('GlobalSharedContext', () => {
|
|
7
|
+
let contextManager;
|
|
8
|
+
beforeEach(async () => {
|
|
9
|
+
resetGlobalSharedContext();
|
|
10
|
+
contextManager = new GlobalSharedContextManager(TEST_CONTEXT_PATH);
|
|
11
|
+
try {
|
|
12
|
+
await fs.rm(path.dirname(TEST_CONTEXT_PATH), { recursive: true, force: true });
|
|
13
|
+
}
|
|
14
|
+
catch { }
|
|
15
|
+
});
|
|
16
|
+
describe('SharedMemory - recentActions', () => {
|
|
17
|
+
it('should add user action', async () => {
|
|
18
|
+
await contextManager.initialize();
|
|
19
|
+
await contextManager.addUserAction('用户要求总结文档', 'agent1', 'channel1', 8);
|
|
20
|
+
const actions = await contextManager.getRecentActions();
|
|
21
|
+
expect(actions).toHaveLength(1);
|
|
22
|
+
expect(actions[0].content).toBe('用户要求总结文档');
|
|
23
|
+
expect(actions[0].agentId).toBe('agent1');
|
|
24
|
+
expect(actions[0].channelId).toBe('channel1');
|
|
25
|
+
expect(actions[0].importance).toBe(8);
|
|
26
|
+
});
|
|
27
|
+
it('should limit recent actions to 50', async () => {
|
|
28
|
+
await contextManager.initialize();
|
|
29
|
+
for (let i = 0; i < 60; i++) {
|
|
30
|
+
await contextManager.addUserAction(`Action ${i}`);
|
|
31
|
+
}
|
|
32
|
+
const actions = await contextManager.getRecentActions(60);
|
|
33
|
+
expect(actions).toHaveLength(50);
|
|
34
|
+
});
|
|
35
|
+
it('should return formatted summary', async () => {
|
|
36
|
+
await contextManager.initialize();
|
|
37
|
+
await contextManager.addUserAction('测试行动1');
|
|
38
|
+
await contextManager.addUserAction('测试行动2');
|
|
39
|
+
const summary = await contextManager.getRecentActionsSummary(10);
|
|
40
|
+
expect(summary).toContain('测试行动1');
|
|
41
|
+
expect(summary).toContain('测试行动2');
|
|
42
|
+
});
|
|
43
|
+
});
|
|
44
|
+
describe('SharedMemory - sharedKnowledge', () => {
|
|
45
|
+
it('should add shared knowledge', async () => {
|
|
46
|
+
await contextManager.initialize();
|
|
47
|
+
await contextManager.addSharedKnowledge('这是一个重要的跨Agent共享知识');
|
|
48
|
+
const knowledge = await contextManager.getSharedKnowledge();
|
|
49
|
+
expect(knowledge).toContain('这是一个重要的跨Agent共享知识');
|
|
50
|
+
});
|
|
51
|
+
it('should not duplicate knowledge', async () => {
|
|
52
|
+
await contextManager.initialize();
|
|
53
|
+
await contextManager.addSharedKnowledge('共享知识');
|
|
54
|
+
await contextManager.addSharedKnowledge('共享知识');
|
|
55
|
+
const knowledge = await contextManager.getSharedKnowledge();
|
|
56
|
+
expect(knowledge.filter(k => k === '共享知识')).toHaveLength(1);
|
|
57
|
+
});
|
|
58
|
+
it('should limit shared knowledge to 100', async () => {
|
|
59
|
+
await contextManager.initialize();
|
|
60
|
+
for (let i = 0; i < 110; i++) {
|
|
61
|
+
await contextManager.addSharedKnowledge(`Knowledge ${i}`);
|
|
62
|
+
}
|
|
63
|
+
const knowledge = await contextManager.getSharedKnowledge();
|
|
64
|
+
expect(knowledge).toHaveLength(100);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
describe('SharedMemory - currentTask', () => {
|
|
68
|
+
it('should set and get current task', async () => {
|
|
69
|
+
await contextManager.initialize();
|
|
70
|
+
const task = await contextManager.setCurrentTask({
|
|
71
|
+
description: '完成文档总结',
|
|
72
|
+
status: 'in_progress'
|
|
73
|
+
});
|
|
74
|
+
expect(task.id).toBeDefined();
|
|
75
|
+
expect(task.description).toBe('完成文档总结');
|
|
76
|
+
expect(task.status).toBe('in_progress');
|
|
77
|
+
expect(task.createdAt).toBeDefined();
|
|
78
|
+
const currentTask = await contextManager.getCurrentTask();
|
|
79
|
+
expect(currentTask?.description).toBe('完成文档总结');
|
|
80
|
+
});
|
|
81
|
+
it('should complete current task', async () => {
|
|
82
|
+
await contextManager.initialize();
|
|
83
|
+
await contextManager.setCurrentTask({
|
|
84
|
+
description: '完成文档总结',
|
|
85
|
+
status: 'in_progress'
|
|
86
|
+
});
|
|
87
|
+
await contextManager.completeCurrentTask('文档总结已完成');
|
|
88
|
+
const currentTask = await contextManager.getCurrentTask();
|
|
89
|
+
expect(currentTask?.status).toBe('completed');
|
|
90
|
+
expect(currentTask?.result).toBe('文档总结已完成');
|
|
91
|
+
expect(currentTask?.completedAt).toBeDefined();
|
|
92
|
+
});
|
|
93
|
+
});
|
|
94
|
+
describe('AgentRegistry', () => {
|
|
95
|
+
it('should register agent', async () => {
|
|
96
|
+
await contextManager.initialize();
|
|
97
|
+
await contextManager.registerAgent({
|
|
98
|
+
agentId: 'agent-001',
|
|
99
|
+
sessionId: 'session-001',
|
|
100
|
+
channelId: 'channel-001',
|
|
101
|
+
capabilities: ['coding', 'writing'],
|
|
102
|
+
status: 'active',
|
|
103
|
+
name: 'TestAgent'
|
|
104
|
+
});
|
|
105
|
+
const agent = await contextManager.getAgent('agent-001');
|
|
106
|
+
expect(agent).toBeDefined();
|
|
107
|
+
expect(agent?.name).toBe('TestAgent');
|
|
108
|
+
expect(agent?.capabilities).toEqual(['coding', 'writing']);
|
|
109
|
+
expect(agent?.status).toBe('active');
|
|
110
|
+
});
|
|
111
|
+
it('should update agent status', async () => {
|
|
112
|
+
await contextManager.initialize();
|
|
113
|
+
await contextManager.registerAgent({
|
|
114
|
+
agentId: 'agent-001',
|
|
115
|
+
sessionId: 'session-001',
|
|
116
|
+
channelId: 'channel-001',
|
|
117
|
+
capabilities: ['coding'],
|
|
118
|
+
status: 'active'
|
|
119
|
+
});
|
|
120
|
+
await contextManager.updateAgentStatus('agent-001', 'busy');
|
|
121
|
+
const agent = await contextManager.getAgent('agent-001');
|
|
122
|
+
expect(agent?.status).toBe('busy');
|
|
123
|
+
});
|
|
124
|
+
it('should get all agents', async () => {
|
|
125
|
+
await contextManager.initialize();
|
|
126
|
+
await contextManager.registerAgent({
|
|
127
|
+
agentId: 'agent-001',
|
|
128
|
+
sessionId: 'session-001',
|
|
129
|
+
channelId: 'channel-001',
|
|
130
|
+
capabilities: ['coding'],
|
|
131
|
+
status: 'active'
|
|
132
|
+
});
|
|
133
|
+
await contextManager.registerAgent({
|
|
134
|
+
agentId: 'agent-002',
|
|
135
|
+
sessionId: 'session-002',
|
|
136
|
+
channelId: 'channel-002',
|
|
137
|
+
capabilities: ['writing'],
|
|
138
|
+
status: 'idle'
|
|
139
|
+
});
|
|
140
|
+
const agents = await contextManager.getAllAgents();
|
|
141
|
+
expect(agents).toHaveLength(2);
|
|
142
|
+
});
|
|
143
|
+
it('should find agents by capability', async () => {
|
|
144
|
+
await contextManager.initialize();
|
|
145
|
+
await contextManager.registerAgent({
|
|
146
|
+
agentId: 'agent-001',
|
|
147
|
+
sessionId: 'session-001',
|
|
148
|
+
channelId: 'channel-001',
|
|
149
|
+
capabilities: ['coding', 'debugging'],
|
|
150
|
+
status: 'active'
|
|
151
|
+
});
|
|
152
|
+
await contextManager.registerAgent({
|
|
153
|
+
agentId: 'agent-002',
|
|
154
|
+
sessionId: 'session-002',
|
|
155
|
+
channelId: 'channel-002',
|
|
156
|
+
capabilities: ['writing', 'editing'],
|
|
157
|
+
status: 'active'
|
|
158
|
+
});
|
|
159
|
+
const codingAgents = await contextManager.findAgentByCapability('coding');
|
|
160
|
+
expect(codingAgents).toHaveLength(1);
|
|
161
|
+
expect(codingAgents[0].agentId).toBe('agent-001');
|
|
162
|
+
});
|
|
163
|
+
it('should get active agents', async () => {
|
|
164
|
+
await contextManager.initialize();
|
|
165
|
+
await contextManager.registerAgent({
|
|
166
|
+
agentId: 'agent-001',
|
|
167
|
+
sessionId: 'session-001',
|
|
168
|
+
channelId: 'channel-001',
|
|
169
|
+
capabilities: ['coding'],
|
|
170
|
+
status: 'active'
|
|
171
|
+
});
|
|
172
|
+
await contextManager.registerAgent({
|
|
173
|
+
agentId: 'agent-002',
|
|
174
|
+
sessionId: 'session-002',
|
|
175
|
+
channelId: 'channel-002',
|
|
176
|
+
capabilities: ['writing'],
|
|
177
|
+
status: 'idle'
|
|
178
|
+
});
|
|
179
|
+
const activeAgents = await contextManager.getActiveAgents();
|
|
180
|
+
expect(activeAgents).toHaveLength(1);
|
|
181
|
+
expect(activeAgents[0].agentId).toBe('agent-001');
|
|
182
|
+
});
|
|
183
|
+
it('should unregister agent', async () => {
|
|
184
|
+
await contextManager.initialize();
|
|
185
|
+
await contextManager.registerAgent({
|
|
186
|
+
agentId: 'agent-001',
|
|
187
|
+
sessionId: 'session-001',
|
|
188
|
+
channelId: 'channel-001',
|
|
189
|
+
capabilities: ['coding'],
|
|
190
|
+
status: 'active'
|
|
191
|
+
});
|
|
192
|
+
await contextManager.unregisterAgent('agent-001');
|
|
193
|
+
const agent = await contextManager.getAgent('agent-001');
|
|
194
|
+
expect(agent).toBeUndefined();
|
|
195
|
+
});
|
|
196
|
+
});
|
|
197
|
+
describe('CooperationQueue', () => {
|
|
198
|
+
it('should create cooperation task', async () => {
|
|
199
|
+
await contextManager.initialize();
|
|
200
|
+
const cooperation = await contextManager.createCooperation('consult', 'agent-001', '请帮我分析这段代码', 'agent-002', 'context here');
|
|
201
|
+
expect(cooperation.id).toBeDefined();
|
|
202
|
+
expect(cooperation.type).toBe('consult');
|
|
203
|
+
expect(cooperation.fromAgentId).toBe('agent-001');
|
|
204
|
+
expect(cooperation.toAgentId).toBe('agent-002');
|
|
205
|
+
expect(cooperation.task).toBe('请帮我分析这段代码');
|
|
206
|
+
expect(cooperation.context).toBe('context here');
|
|
207
|
+
expect(cooperation.status).toBe('pending');
|
|
208
|
+
});
|
|
209
|
+
it('should update cooperation status', async () => {
|
|
210
|
+
await contextManager.initialize();
|
|
211
|
+
const cooperation = await contextManager.createCooperation('delegate', 'agent-001', '完成这个任务');
|
|
212
|
+
await contextManager.updateCooperationStatus(cooperation.id, 'in_progress');
|
|
213
|
+
const updated = await contextManager.getCooperation(cooperation.id);
|
|
214
|
+
expect(updated?.status).toBe('in_progress');
|
|
215
|
+
});
|
|
216
|
+
it('should get pending cooperations for agent', async () => {
|
|
217
|
+
await contextManager.initialize();
|
|
218
|
+
await contextManager.createCooperation('consult', 'agent-001', 'Task 1', 'agent-002');
|
|
219
|
+
await contextManager.createCooperation('delegate', 'agent-001', 'Task 2');
|
|
220
|
+
const pending = await contextManager.getPendingCooperations('agent-001');
|
|
221
|
+
expect(pending).toHaveLength(2);
|
|
222
|
+
});
|
|
223
|
+
it('should get cooperations for specific agent', async () => {
|
|
224
|
+
await contextManager.initialize();
|
|
225
|
+
await contextManager.createCooperation('consult', 'agent-001', 'Task for agent-002', 'agent-002');
|
|
226
|
+
await contextManager.createCooperation('delegate', 'agent-003', 'Task for agent-003', 'agent-003');
|
|
227
|
+
const agent002Coops = await contextManager.getCooperationsForAgent('agent-002');
|
|
228
|
+
expect(agent002Coops).toHaveLength(1);
|
|
229
|
+
expect(agent002Coops[0].task).toBe('Task for agent-002');
|
|
230
|
+
});
|
|
231
|
+
it('should add result to cooperation', async () => {
|
|
232
|
+
await contextManager.initialize();
|
|
233
|
+
const cooperation = await contextManager.createCooperation('consult', 'agent-001', '请分析');
|
|
234
|
+
await contextManager.updateCooperationStatus(cooperation.id, 'done', '分析结果:代码有bug');
|
|
235
|
+
const updated = await contextManager.getCooperation(cooperation.id);
|
|
236
|
+
expect(updated?.status).toBe('done');
|
|
237
|
+
expect(updated?.result).toBe('分析结果:代码有bug');
|
|
238
|
+
});
|
|
239
|
+
});
|
|
240
|
+
describe('Full context', () => {
|
|
241
|
+
it('should get full context', async () => {
|
|
242
|
+
await contextManager.initialize();
|
|
243
|
+
await contextManager.addUserAction('Test action');
|
|
244
|
+
await contextManager.addSharedKnowledge('Test knowledge');
|
|
245
|
+
await contextManager.registerAgent({
|
|
246
|
+
agentId: 'agent-001',
|
|
247
|
+
sessionId: 'session-001',
|
|
248
|
+
channelId: 'channel-001',
|
|
249
|
+
capabilities: ['coding'],
|
|
250
|
+
status: 'active'
|
|
251
|
+
});
|
|
252
|
+
const fullContext = await contextManager.getFullContext();
|
|
253
|
+
expect(fullContext.memory.recentActions).toHaveLength(1);
|
|
254
|
+
expect(fullContext.memory.sharedKnowledge).toHaveLength(1);
|
|
255
|
+
expect(fullContext.agentRegistry['agent-001']).toBeDefined();
|
|
256
|
+
});
|
|
257
|
+
it('should get context summary', async () => {
|
|
258
|
+
await contextManager.initialize();
|
|
259
|
+
await contextManager.addUserAction('用户执行了操作A');
|
|
260
|
+
await contextManager.registerAgent({
|
|
261
|
+
agentId: 'agent-001',
|
|
262
|
+
sessionId: 'session-001',
|
|
263
|
+
channelId: 'channel-001',
|
|
264
|
+
capabilities: ['coding'],
|
|
265
|
+
status: 'active',
|
|
266
|
+
name: '编码助手'
|
|
267
|
+
});
|
|
268
|
+
const summary = await contextManager.getContextSummary();
|
|
269
|
+
expect(summary).toContain('全局共享上下文');
|
|
270
|
+
expect(summary).toContain('最近行动');
|
|
271
|
+
expect(summary).toContain('用户执行了操作A');
|
|
272
|
+
expect(summary).toContain('Agent 注册');
|
|
273
|
+
expect(summary).toContain('编码助手');
|
|
274
|
+
});
|
|
275
|
+
});
|
|
276
|
+
describe('Persistence', () => {
|
|
277
|
+
it('should persist and reload context', async () => {
|
|
278
|
+
await contextManager.initialize();
|
|
279
|
+
await contextManager.addUserAction('持久化测试');
|
|
280
|
+
await contextManager.registerAgent({
|
|
281
|
+
agentId: 'agent-001',
|
|
282
|
+
sessionId: 'session-001',
|
|
283
|
+
channelId: 'channel-001',
|
|
284
|
+
capabilities: ['coding'],
|
|
285
|
+
status: 'active'
|
|
286
|
+
});
|
|
287
|
+
const newManager = new GlobalSharedContextManager(TEST_CONTEXT_PATH);
|
|
288
|
+
await newManager.initialize();
|
|
289
|
+
const actions = await newManager.getRecentActions();
|
|
290
|
+
expect(actions).toHaveLength(1);
|
|
291
|
+
expect(actions[0].content).toBe('持久化测试');
|
|
292
|
+
const agent = await newManager.getAgent('agent-001');
|
|
293
|
+
expect(agent).toBeDefined();
|
|
294
|
+
});
|
|
295
|
+
});
|
|
296
|
+
describe('Clear', () => {
|
|
297
|
+
it('should clear all data', async () => {
|
|
298
|
+
await contextManager.initialize();
|
|
299
|
+
await contextManager.addUserAction('Test action');
|
|
300
|
+
await contextManager.addSharedKnowledge('Test knowledge');
|
|
301
|
+
await contextManager.registerAgent({
|
|
302
|
+
agentId: 'agent-001',
|
|
303
|
+
sessionId: 'session-001',
|
|
304
|
+
channelId: 'channel-001',
|
|
305
|
+
capabilities: ['coding'],
|
|
306
|
+
status: 'active'
|
|
307
|
+
});
|
|
308
|
+
await contextManager.clear();
|
|
309
|
+
const context = await contextManager.getFullContext();
|
|
310
|
+
expect(context.memory.recentActions).toHaveLength(0);
|
|
311
|
+
expect(context.memory.sharedKnowledge).toHaveLength(0);
|
|
312
|
+
expect(Object.keys(context.agentRegistry)).toHaveLength(0);
|
|
313
|
+
});
|
|
314
|
+
});
|
|
315
|
+
});
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
2
|
+
import { generateJudgmentInjection, getCoreJudgmentsForSession, getJudgmentsForPath, getJudgmentsForFragment, getJudgmentsForContextRequest, } from '../bollharness-integration/context-router-judgment.js';
|
|
3
|
+
import * as judgmentModule from '../pi-ecosystem-judgment/index.js';
|
|
4
|
+
describe('Harness Judgment Injection - Gate Integration', () => {
|
|
5
|
+
beforeEach(() => {
|
|
6
|
+
vi.clearAllMocks();
|
|
7
|
+
});
|
|
8
|
+
describe('Gate-specific judgment injection', () => {
|
|
9
|
+
it('should inject core judgments at Gate 0 (session start)', async () => {
|
|
10
|
+
const injection = await generateJudgmentInjection('src/agents/', 0);
|
|
11
|
+
expect(injection).toContain('# User Core Values');
|
|
12
|
+
expect(injection).toContain('core_judgments:');
|
|
13
|
+
expect(injection).toContain('confidence: 0.9');
|
|
14
|
+
});
|
|
15
|
+
it('should inject path judgments at Gate 3 (plan freeze)', async () => {
|
|
16
|
+
const injection = await generateJudgmentInjection('src/agents/', 3);
|
|
17
|
+
expect(injection).toContain('# Plan Freeze');
|
|
18
|
+
expect(injection).toContain('active_judgments:');
|
|
19
|
+
});
|
|
20
|
+
it('should return path judgments for Gate 1 (not core)', async () => {
|
|
21
|
+
const injection = await generateJudgmentInjection('src/agents/', 1);
|
|
22
|
+
expect(injection).toContain('# Gate 1');
|
|
23
|
+
expect(injection).not.toContain('core_judgments:');
|
|
24
|
+
});
|
|
25
|
+
it('should include confidence in injection header', async () => {
|
|
26
|
+
const injection = await generateJudgmentInjection('src/agents/', 3);
|
|
27
|
+
expect(injection).toMatch(/# Confidence: \d+%/);
|
|
28
|
+
});
|
|
29
|
+
it('should include file path in injection header', async () => {
|
|
30
|
+
const injection = await generateJudgmentInjection('src/agents/', 3);
|
|
31
|
+
expect(injection).toContain('# Path: src/agents/');
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
describe('Path-based judgment routing', () => {
|
|
35
|
+
it('should route src/agents/ to agent-related fragments', async () => {
|
|
36
|
+
const result = await getJudgmentsForPath('src/agents/');
|
|
37
|
+
expect(result.fragments).toBeDefined();
|
|
38
|
+
expect(Array.isArray(result.fragments)).toBe(true);
|
|
39
|
+
});
|
|
40
|
+
it('should return judgments sorted by confidence', async () => {
|
|
41
|
+
const result = await getJudgmentsForPath('src/agents/');
|
|
42
|
+
if (result.judgments.length > 1) {
|
|
43
|
+
for (let i = 1; i < result.judgments.length; i++) {
|
|
44
|
+
expect(result.judgments[i - 1].confidence).toBeGreaterThanOrEqual(result.judgments[i].confidence);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
it('should filter judgments by minimum confidence', async () => {
|
|
49
|
+
const result = await getJudgmentsForPath('src/agents/', { minConfidence: 0.9 });
|
|
50
|
+
for (const j of result.judgments) {
|
|
51
|
+
expect(j.confidence).toBeGreaterThanOrEqual(0.9);
|
|
52
|
+
}
|
|
53
|
+
});
|
|
54
|
+
it('should limit number of judgments', async () => {
|
|
55
|
+
const result = await getJudgmentsForPath('src/agents/', { maxJudgments: 3 });
|
|
56
|
+
expect(result.judgments.length).toBeLessThanOrEqual(3);
|
|
57
|
+
});
|
|
58
|
+
it('should calculate overall confidence for path', async () => {
|
|
59
|
+
const result = await getJudgmentsForPath('src/agents/');
|
|
60
|
+
expect(typeof result.confidence).toBe('number');
|
|
61
|
+
expect(result.confidence).toBeGreaterThanOrEqual(0);
|
|
62
|
+
expect(result.confidence).toBeLessThanOrEqual(1);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
65
|
+
describe('Fragment to judgment mapping', () => {
|
|
66
|
+
it('should map agent-architecture fragment to agent contexts', async () => {
|
|
67
|
+
const judgments = await getJudgmentsForFragment('agent-architecture');
|
|
68
|
+
expect(Array.isArray(judgments)).toBe(true);
|
|
69
|
+
});
|
|
70
|
+
it('should map testing-patterns fragment to testing contexts', async () => {
|
|
71
|
+
const judgments = await getJudgmentsForFragment('testing-patterns');
|
|
72
|
+
expect(Array.isArray(judgments)).toBe(true);
|
|
73
|
+
});
|
|
74
|
+
it('should return empty for unknown fragment', async () => {
|
|
75
|
+
const judgments = await getJudgmentsForFragment('unknown-fragment-xyz');
|
|
76
|
+
expect(Array.isArray(judgments)).toBe(true);
|
|
77
|
+
});
|
|
78
|
+
it('should deduplicate judgments across fragments', async () => {
|
|
79
|
+
const result = await getJudgmentsForPath('src/agents/');
|
|
80
|
+
const ids = result.judgments.map(j => j.id);
|
|
81
|
+
const uniqueIds = new Set(ids);
|
|
82
|
+
expect(ids.length).toBe(uniqueIds.size);
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
describe('Core judgments for session', () => {
|
|
86
|
+
it('should only include human source judgments', async () => {
|
|
87
|
+
const injection = await getCoreJudgmentsForSession(0.9);
|
|
88
|
+
if (injection.length > 0) {
|
|
89
|
+
expect(injection).toContain('core_judgments:');
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
it('should filter by minimum confidence', async () => {
|
|
93
|
+
const injection = await getCoreJudgmentsForSession(0.95);
|
|
94
|
+
if (injection.length > 0) {
|
|
95
|
+
expect(injection).toContain('confidence: 0.95');
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
it('should limit to 10 judgments', async () => {
|
|
99
|
+
const injection = await getCoreJudgmentsForSession(0.5);
|
|
100
|
+
const matches = injection.match(/principle:/g);
|
|
101
|
+
if (matches) {
|
|
102
|
+
expect(matches.length).toBeLessThanOrEqual(10);
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
it('should return empty string when no judgments meet threshold', async () => {
|
|
106
|
+
const injection = await getCoreJudgmentsForSession(1.0);
|
|
107
|
+
expect(typeof injection).toBe('string');
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
describe('Judgment formatting', () => {
|
|
111
|
+
it('should format judgments as YAML by default', async () => {
|
|
112
|
+
const result = await getJudgmentsForPath('src/agents/', { format: 'yaml' });
|
|
113
|
+
expect(result.contextYaml).toContain('active_judgments:');
|
|
114
|
+
});
|
|
115
|
+
it('should format judgments as JSON', async () => {
|
|
116
|
+
const result = await getJudgmentsForPath('src/agents/', { format: 'json' });
|
|
117
|
+
expect(result.contextYaml).toContain('[');
|
|
118
|
+
expect(() => JSON.parse(result.contextYaml)).not.toThrow();
|
|
119
|
+
});
|
|
120
|
+
it('should format judgments as text', async () => {
|
|
121
|
+
const result = await getJudgmentsForPath('src/agents/', { format: 'text' });
|
|
122
|
+
expect(result.contextYaml).toMatch(/\[\d+%\]/);
|
|
123
|
+
});
|
|
124
|
+
it('should escape YAML strings correctly', async () => {
|
|
125
|
+
const result = await getJudgmentsForPath('src/agents/', { format: 'yaml' });
|
|
126
|
+
expect(result.contextYaml).not.toContain('\n"');
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
describe('Context-specific judgment requests', () => {
|
|
130
|
+
it('should get judgments for explicit context', async () => {
|
|
131
|
+
const result = await getJudgmentsForContextRequest('typescript');
|
|
132
|
+
expect(result).toHaveProperty('judgments');
|
|
133
|
+
expect(result).toHaveProperty('confidence');
|
|
134
|
+
expect(result).toHaveProperty('contextYaml');
|
|
135
|
+
});
|
|
136
|
+
it('should filter by context match', async () => {
|
|
137
|
+
const result = await getJudgmentsForContextRequest('code-quality');
|
|
138
|
+
for (const j of result.judgments) {
|
|
139
|
+
const hasMatch = j.context?.toLowerCase().includes('code-quality') ||
|
|
140
|
+
j.context?.toLowerCase().includes('quality') ||
|
|
141
|
+
j.context?.toLowerCase().includes('development');
|
|
142
|
+
expect(hasMatch).toBeTruthy();
|
|
143
|
+
}
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
});
|
|
147
|
+
describe('Harness Judgment Injection - Multi-Agent Scenarios', () => {
|
|
148
|
+
beforeEach(() => {
|
|
149
|
+
vi.clearAllMocks();
|
|
150
|
+
});
|
|
151
|
+
describe('Decision level with harness context', () => {
|
|
152
|
+
it('should route consult_internal to colony_ant and subagent', async () => {
|
|
153
|
+
vi.spyOn(judgmentModule, 'calculateConfidence').mockReturnValueOnce(0.5);
|
|
154
|
+
const { evaluateDecision } = await import('../pi-ecosystem-judgment/decision.js');
|
|
155
|
+
const request = await evaluateDecision('Delegate task to colony ant', 'delegation', 'agent-001', 0.7);
|
|
156
|
+
expect(request.targets).toContain('colony_ant');
|
|
157
|
+
expect(request.targets).toContain('subagent');
|
|
158
|
+
expect(request.targets).not.toContain('p2p_agent');
|
|
159
|
+
});
|
|
160
|
+
it('should route consult_external to p2p_agent', async () => {
|
|
161
|
+
vi.spyOn(judgmentModule, 'calculateConfidence').mockReturnValueOnce(0.35);
|
|
162
|
+
const { evaluateDecision } = await import('../pi-ecosystem-judgment/decision.js');
|
|
163
|
+
const request = await evaluateDecision('Cross-system protocol negotiation', 'protocol', 'agent-001', 0.7);
|
|
164
|
+
expect(request.targets).toContain('p2p_agent');
|
|
165
|
+
expect(request.targets).toContain('colony_ant');
|
|
166
|
+
expect(request.targets).toContain('subagent');
|
|
167
|
+
});
|
|
168
|
+
it('should escalate to human for strategic decisions', async () => {
|
|
169
|
+
vi.spyOn(judgmentModule, 'calculateConfidence').mockReturnValueOnce(0.2);
|
|
170
|
+
const { evaluateDecision } = await import('../pi-ecosystem-judgment/decision.js');
|
|
171
|
+
const request = await evaluateDecision('Strategic pivot decision', 'strategy', 'agent-001', 0.7);
|
|
172
|
+
expect(request.targets).toEqual(['human']);
|
|
173
|
+
});
|
|
174
|
+
});
|
|
175
|
+
describe('Judgment confidence propagation', () => {
|
|
176
|
+
it('should use harness path confidence for decision routing', async () => {
|
|
177
|
+
const result = await getJudgmentsForPath('src/agents/');
|
|
178
|
+
vi.spyOn(judgmentModule, 'calculateConfidence').mockReturnValueOnce(result.confidence);
|
|
179
|
+
const { evaluateDecision } = await import('../pi-ecosystem-judgment/decision.js');
|
|
180
|
+
const request = await evaluateDecision('Agent architecture decision', 'architecture', 'agent-001', 0.7);
|
|
181
|
+
if (result.confidence >= 0.7) {
|
|
182
|
+
expect(request.level).toBe('autonomous');
|
|
183
|
+
}
|
|
184
|
+
else if (result.confidence >= 0.49) {
|
|
185
|
+
expect(request.level).toBe('consult_internal');
|
|
186
|
+
}
|
|
187
|
+
else if (result.confidence >= 0.28) {
|
|
188
|
+
expect(request.level).toBe('consult_external');
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
expect(request.level).toBe('require_human');
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
});
|
|
195
|
+
});
|
|
196
|
+
describe('Harness Judgment Injection - Gate Confidence Thresholds', () => {
|
|
197
|
+
const gateThresholds = [
|
|
198
|
+
{ gate: 0, expectedMinConfidence: 0.9, description: 'Session start - highest bar' },
|
|
199
|
+
{ gate: 1, expectedMinConfidence: 0.8, description: 'Architecture design' },
|
|
200
|
+
{ gate: 2, expectedMinConfidence: 0.75, description: 'Review' },
|
|
201
|
+
{ gate: 3, expectedMinConfidence: 0.8, description: 'Plan freeze' },
|
|
202
|
+
{ gate: 5, expectedMinConfidence: 0.7, description: 'Task architecture' },
|
|
203
|
+
{ gate: 7, expectedMinConfidence: 0.7, description: 'Execution' },
|
|
204
|
+
];
|
|
205
|
+
it.each(gateThresholds)('Gate $gate ($description) should use minConfidence $expectedMinConfidence', async ({ gate, expectedMinConfidence }) => {
|
|
206
|
+
const injection = await generateJudgmentInjection('src/agents/', gate);
|
|
207
|
+
if (gate === 0 || gate === 1 || gate === 2 || gate === 3 || gate === 5 || gate === 7) {
|
|
208
|
+
expect(injection).toBeDefined();
|
|
209
|
+
expect(typeof injection).toBe('string');
|
|
210
|
+
}
|
|
211
|
+
});
|
|
212
|
+
it('should return path judgments for all non-zero gates', async () => {
|
|
213
|
+
for (const gate of [1, 2, 4, 5, 6, 8, 9]) {
|
|
214
|
+
const injection = await generateJudgmentInjection('src/agents/', gate);
|
|
215
|
+
expect(typeof injection).toBe('string');
|
|
216
|
+
}
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
describe('Harness Judgment Injection - End-to-End Flow', () => {
|
|
220
|
+
it('should produce injectable YAML for agent context', async () => {
|
|
221
|
+
const injection = await generateJudgmentInjection('src/agents/', 0);
|
|
222
|
+
const hasValidYamlStructure = injection.includes('core_judgments:') ||
|
|
223
|
+
injection.includes('active_judgments:') ||
|
|
224
|
+
injection.includes('# User Core Values');
|
|
225
|
+
expect(hasValidYamlStructure).toBeTruthy();
|
|
226
|
+
});
|
|
227
|
+
it('should format judgments for LLM consumption', async () => {
|
|
228
|
+
const result = await getJudgmentsForPath('src/agents/', { format: 'yaml' });
|
|
229
|
+
const lines = result.contextYaml.split('\n');
|
|
230
|
+
const hasPrinciple = lines.some(line => line.includes('principle:'));
|
|
231
|
+
const hasConfidence = lines.some(line => line.includes('confidence:'));
|
|
232
|
+
expect(hasPrinciple || hasConfidence).toBeTruthy();
|
|
233
|
+
});
|
|
234
|
+
it('should fallback to general-dev-principles for unknown paths', async () => {
|
|
235
|
+
const result = await getJudgmentsForPath('/nonexistent/path/that/matches/nothing');
|
|
236
|
+
expect(result).toHaveProperty('judgments');
|
|
237
|
+
expect(result).toHaveProperty('confidence');
|
|
238
|
+
expect(result.fragments).toContain('general-dev-principles');
|
|
239
|
+
});
|
|
240
|
+
it('should provide traceability from path to fragment to judgment', async () => {
|
|
241
|
+
const result = await getJudgmentsForPath('src/agents/');
|
|
242
|
+
expect(result.fragments.length).toBeGreaterThan(0);
|
|
243
|
+
expect(result.judgments.length).toBeGreaterThanOrEqual(0);
|
|
244
|
+
expect(typeof result.confidence).toBe('number');
|
|
245
|
+
});
|
|
246
|
+
});
|