dialectic 0.1.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/.cursor/commands/setup-test.mdc +175 -0
- package/.cursor/rules/basic-code-cleanup.mdc +1110 -0
- package/.cursor/rules/riper5.mdc +96 -0
- package/.env.example +6 -0
- package/AGENTS.md +1052 -0
- package/LICENSE +21 -0
- package/README.md +93 -0
- package/WARP.md +113 -0
- package/dialectic-1.0.0.tgz +0 -0
- package/dialectic.js +10 -0
- package/docs/commands.md +375 -0
- package/docs/configuration.md +882 -0
- package/docs/context_summarization.md +1023 -0
- package/docs/debate_flow.md +1127 -0
- package/docs/eval_flow.md +795 -0
- package/docs/evaluator.md +141 -0
- package/examples/debate-config-openrouter.json +48 -0
- package/examples/debate_config1.json +48 -0
- package/examples/eval/eval1/eval_config1.json +13 -0
- package/examples/eval/eval1/result1.json +62 -0
- package/examples/eval/eval1/result2.json +97 -0
- package/examples/eval_summary_format.md +11 -0
- package/examples/example3/debate-config.json +64 -0
- package/examples/example3/eval_config2.json +25 -0
- package/examples/example3/problem.md +17 -0
- package/examples/example3/rounds_test/eval_run.sh +16 -0
- package/examples/example3/rounds_test/run_test.sh +16 -0
- package/examples/kata1/architect-only-solution_2-rounds.json +121 -0
- package/examples/kata1/architect-perf-solution_2-rounds.json +234 -0
- package/examples/kata1/debate-config-kata1.json +54 -0
- package/examples/kata1/eval_architect-only_2-rounds.json +97 -0
- package/examples/kata1/eval_architect-perf_2-rounds.json +97 -0
- package/examples/kata1/kata1-report.md +12224 -0
- package/examples/kata1/kata1-report_temps-01_01_01_07.md +2451 -0
- package/examples/kata1/kata1.md +5 -0
- package/examples/kata1/meta.txt +1 -0
- package/examples/kata2/debate-config.json +54 -0
- package/examples/kata2/eval_config1.json +21 -0
- package/examples/kata2/eval_config2.json +25 -0
- package/examples/kata2/kata2.md +5 -0
- package/examples/kata2/only_architect/debate-config.json +45 -0
- package/examples/kata2/only_architect/eval_run.sh +11 -0
- package/examples/kata2/only_architect/run_test.sh +5 -0
- package/examples/kata2/rounds_test/eval_run.sh +11 -0
- package/examples/kata2/rounds_test/run_test.sh +5 -0
- package/examples/kata2/summary_length_test/eval_run.sh +11 -0
- package/examples/kata2/summary_length_test/eval_run_w_clarify.sh +7 -0
- package/examples/kata2/summary_length_test/run_test.sh +5 -0
- package/examples/task-queue/debate-config.json +76 -0
- package/examples/task-queue/debate_report.md +566 -0
- package/examples/task-queue/task-queue-system.md +25 -0
- package/jest.config.ts +13 -0
- package/multi_agent_debate_spec.md +2980 -0
- package/package.json +38 -0
- package/sanity-check-problem.txt +9 -0
- package/src/agents/prompts/architect-prompts.ts +203 -0
- package/src/agents/prompts/generalist-prompts.ts +157 -0
- package/src/agents/prompts/index.ts +41 -0
- package/src/agents/prompts/judge-prompts.ts +19 -0
- package/src/agents/prompts/kiss-prompts.ts +230 -0
- package/src/agents/prompts/performance-prompts.ts +142 -0
- package/src/agents/prompts/prompt-types.ts +68 -0
- package/src/agents/prompts/security-prompts.ts +149 -0
- package/src/agents/prompts/shared.ts +144 -0
- package/src/agents/prompts/testing-prompts.ts +149 -0
- package/src/agents/role-based-agent.ts +386 -0
- package/src/cli/commands/debate.ts +761 -0
- package/src/cli/commands/eval.ts +475 -0
- package/src/cli/commands/report.ts +265 -0
- package/src/cli/index.ts +79 -0
- package/src/core/agent.ts +198 -0
- package/src/core/clarifications.ts +34 -0
- package/src/core/judge.ts +257 -0
- package/src/core/orchestrator.ts +432 -0
- package/src/core/state-manager.ts +322 -0
- package/src/eval/evaluator-agent.ts +130 -0
- package/src/eval/prompts/system.md +41 -0
- package/src/eval/prompts/user.md +64 -0
- package/src/providers/llm-provider.ts +25 -0
- package/src/providers/openai-provider.ts +84 -0
- package/src/providers/openrouter-provider.ts +122 -0
- package/src/providers/provider-factory.ts +64 -0
- package/src/types/agent.types.ts +141 -0
- package/src/types/config.types.ts +47 -0
- package/src/types/debate.types.ts +237 -0
- package/src/types/eval.types.ts +85 -0
- package/src/utils/common.ts +104 -0
- package/src/utils/context-formatter.ts +102 -0
- package/src/utils/context-summarizer.ts +143 -0
- package/src/utils/env-loader.ts +46 -0
- package/src/utils/exit-codes.ts +5 -0
- package/src/utils/id.ts +11 -0
- package/src/utils/logger.ts +48 -0
- package/src/utils/paths.ts +10 -0
- package/src/utils/progress-ui.ts +313 -0
- package/src/utils/prompt-loader.ts +79 -0
- package/src/utils/report-generator.ts +301 -0
- package/tests/clarifications.spec.ts +128 -0
- package/tests/cli.debate.spec.ts +144 -0
- package/tests/config-loading.spec.ts +206 -0
- package/tests/context-summarizer.spec.ts +131 -0
- package/tests/debate-config-custom.json +38 -0
- package/tests/env-loader.spec.ts +149 -0
- package/tests/eval.command.spec.ts +1191 -0
- package/tests/logger.spec.ts +19 -0
- package/tests/openai-provider.spec.ts +26 -0
- package/tests/openrouter-provider.spec.ts +279 -0
- package/tests/orchestrator-summary.spec.ts +386 -0
- package/tests/orchestrator.spec.ts +207 -0
- package/tests/prompt-loader.spec.ts +52 -0
- package/tests/prompts/architect.md +16 -0
- package/tests/provider-factory.spec.ts +150 -0
- package/tests/report.command.spec.ts +546 -0
- package/tests/role-based-agent-summary.spec.ts +476 -0
- package/tests/security-agent.spec.ts +221 -0
- package/tests/shared-prompts.spec.ts +318 -0
- package/tests/state-manager.spec.ts +251 -0
- package/tests/summary-prompts.spec.ts +153 -0
- package/tsconfig.json +49 -0
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
import {
|
|
2
|
+
appendSharedInstructions,
|
|
3
|
+
INSTRUCTION_TYPES,
|
|
4
|
+
getSharedSystemInstructions,
|
|
5
|
+
getSharedProposalInstructions,
|
|
6
|
+
getSharedCritiqueInstructions,
|
|
7
|
+
getSharedRefinementInstructions,
|
|
8
|
+
getSharedSummarizationInstructions
|
|
9
|
+
} from '../src/agents/prompts/shared';
|
|
10
|
+
|
|
11
|
+
describe('Shared Prompts', () => {
|
|
12
|
+
describe('INSTRUCTION_TYPES constants', () => {
|
|
13
|
+
it('should export all required instruction type constants', () => {
|
|
14
|
+
expect(INSTRUCTION_TYPES.SYSTEM).toBeDefined();
|
|
15
|
+
expect(INSTRUCTION_TYPES.PROPOSAL).toBeDefined();
|
|
16
|
+
expect(INSTRUCTION_TYPES.CRITIQUE).toBeDefined();
|
|
17
|
+
expect(INSTRUCTION_TYPES.REFINEMENT).toBeDefined();
|
|
18
|
+
expect(INSTRUCTION_TYPES.SUMMARIZATION).toBeDefined();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
it('should have correct string values', () => {
|
|
22
|
+
expect(INSTRUCTION_TYPES.SYSTEM).toBe('system');
|
|
23
|
+
expect(INSTRUCTION_TYPES.PROPOSAL).toBe('proposal');
|
|
24
|
+
expect(INSTRUCTION_TYPES.CRITIQUE).toBe('critique');
|
|
25
|
+
expect(INSTRUCTION_TYPES.REFINEMENT).toBe('refinement');
|
|
26
|
+
expect(INSTRUCTION_TYPES.SUMMARIZATION).toBe('summarization');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('should be usable in function calls', () => {
|
|
30
|
+
const result = appendSharedInstructions('test prompt', INSTRUCTION_TYPES.SYSTEM);
|
|
31
|
+
expect(result).toBeDefined();
|
|
32
|
+
expect(typeof result).toBe('string');
|
|
33
|
+
expect(result.length).toBeGreaterThan('test prompt'.length);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe('Individual instruction functions', () => {
|
|
38
|
+
it('should return non-empty strings for all instruction types', () => {
|
|
39
|
+
expect(getSharedSystemInstructions()).toBeDefined();
|
|
40
|
+
expect(getSharedSystemInstructions().length).toBeGreaterThan(0);
|
|
41
|
+
|
|
42
|
+
expect(getSharedProposalInstructions()).toBeDefined();
|
|
43
|
+
expect(getSharedProposalInstructions().length).toBeGreaterThan(0);
|
|
44
|
+
|
|
45
|
+
expect(getSharedCritiqueInstructions()).toBeDefined();
|
|
46
|
+
expect(getSharedCritiqueInstructions().length).toBeGreaterThan(0);
|
|
47
|
+
|
|
48
|
+
expect(getSharedRefinementInstructions()).toBeDefined();
|
|
49
|
+
expect(getSharedRefinementInstructions().length).toBeGreaterThan(0);
|
|
50
|
+
|
|
51
|
+
expect(getSharedSummarizationInstructions()).toBeDefined();
|
|
52
|
+
expect(getSharedSummarizationInstructions().length).toBeGreaterThan(0);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('should return different content for different instruction types', () => {
|
|
56
|
+
const systemInstructions = getSharedSystemInstructions();
|
|
57
|
+
const proposalInstructions = getSharedProposalInstructions();
|
|
58
|
+
const critiqueInstructions = getSharedCritiqueInstructions();
|
|
59
|
+
const refinementInstructions = getSharedRefinementInstructions();
|
|
60
|
+
const summarizationInstructions = getSharedSummarizationInstructions();
|
|
61
|
+
|
|
62
|
+
// All should be different from each other
|
|
63
|
+
expect(systemInstructions).not.toBe(proposalInstructions);
|
|
64
|
+
expect(systemInstructions).not.toBe(critiqueInstructions);
|
|
65
|
+
expect(systemInstructions).not.toBe(refinementInstructions);
|
|
66
|
+
expect(systemInstructions).not.toBe(summarizationInstructions);
|
|
67
|
+
|
|
68
|
+
expect(proposalInstructions).not.toBe(critiqueInstructions);
|
|
69
|
+
expect(proposalInstructions).not.toBe(refinementInstructions);
|
|
70
|
+
expect(proposalInstructions).not.toBe(summarizationInstructions);
|
|
71
|
+
|
|
72
|
+
expect(critiqueInstructions).not.toBe(refinementInstructions);
|
|
73
|
+
expect(critiqueInstructions).not.toBe(summarizationInstructions);
|
|
74
|
+
|
|
75
|
+
expect(refinementInstructions).not.toBe(summarizationInstructions);
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it('should return consistent results across multiple calls', () => {
|
|
79
|
+
const system1 = getSharedSystemInstructions();
|
|
80
|
+
const system2 = getSharedSystemInstructions();
|
|
81
|
+
expect(system1).toBe(system2);
|
|
82
|
+
|
|
83
|
+
const proposal1 = getSharedProposalInstructions();
|
|
84
|
+
const proposal2 = getSharedProposalInstructions();
|
|
85
|
+
expect(proposal1).toBe(proposal2);
|
|
86
|
+
|
|
87
|
+
const critique1 = getSharedCritiqueInstructions();
|
|
88
|
+
const critique2 = getSharedCritiqueInstructions();
|
|
89
|
+
expect(critique1).toBe(critique2);
|
|
90
|
+
|
|
91
|
+
const refinement1 = getSharedRefinementInstructions();
|
|
92
|
+
const refinement2 = getSharedRefinementInstructions();
|
|
93
|
+
expect(refinement1).toBe(refinement2);
|
|
94
|
+
|
|
95
|
+
const summarization1 = getSharedSummarizationInstructions();
|
|
96
|
+
const summarization2 = getSharedSummarizationInstructions();
|
|
97
|
+
expect(summarization1).toBe(summarization2);
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
describe('appendSharedInstructions() - Basic functionality', () => {
|
|
102
|
+
it('should append system instructions correctly', () => {
|
|
103
|
+
const prompt = 'You are an expert.';
|
|
104
|
+
const result = appendSharedInstructions(prompt, INSTRUCTION_TYPES.SYSTEM);
|
|
105
|
+
|
|
106
|
+
expect(result).toBeDefined();
|
|
107
|
+
expect(typeof result).toBe('string');
|
|
108
|
+
expect(result).toContain(prompt);
|
|
109
|
+
expect(result.length).toBeGreaterThan(prompt.length);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('should append proposal instructions correctly', () => {
|
|
113
|
+
const prompt = 'Solve this problem.';
|
|
114
|
+
const result = appendSharedInstructions(prompt, INSTRUCTION_TYPES.PROPOSAL);
|
|
115
|
+
|
|
116
|
+
expect(result).toBeDefined();
|
|
117
|
+
expect(typeof result).toBe('string');
|
|
118
|
+
expect(result).toContain(prompt);
|
|
119
|
+
expect(result.length).toBeGreaterThan(prompt.length);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('should append critique instructions correctly', () => {
|
|
123
|
+
const prompt = 'Review this proposal.';
|
|
124
|
+
const result = appendSharedInstructions(prompt, INSTRUCTION_TYPES.CRITIQUE);
|
|
125
|
+
|
|
126
|
+
expect(result).toBeDefined();
|
|
127
|
+
expect(typeof result).toBe('string');
|
|
128
|
+
expect(result).toContain(prompt);
|
|
129
|
+
expect(result.length).toBeGreaterThan(prompt.length);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('should append refinement instructions correctly', () => {
|
|
133
|
+
const prompt = 'Refine your solution.';
|
|
134
|
+
const result = appendSharedInstructions(prompt, INSTRUCTION_TYPES.REFINEMENT);
|
|
135
|
+
|
|
136
|
+
expect(result).toBeDefined();
|
|
137
|
+
expect(typeof result).toBe('string');
|
|
138
|
+
expect(result).toContain(prompt);
|
|
139
|
+
expect(result.length).toBeGreaterThan(prompt.length);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
it('should append summarization instructions correctly', () => {
|
|
143
|
+
const prompt = 'Summarize the debate.';
|
|
144
|
+
const result = appendSharedInstructions(prompt, INSTRUCTION_TYPES.SUMMARIZATION);
|
|
145
|
+
|
|
146
|
+
expect(result).toBeDefined();
|
|
147
|
+
expect(typeof result).toBe('string');
|
|
148
|
+
expect(result).toContain(prompt);
|
|
149
|
+
expect(result.length).toBeGreaterThan(prompt.length);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it('should return original prompt plus appended instructions', () => {
|
|
153
|
+
const prompt = 'Test prompt content';
|
|
154
|
+
const result = appendSharedInstructions(prompt, INSTRUCTION_TYPES.SYSTEM);
|
|
155
|
+
|
|
156
|
+
// Should start with original prompt
|
|
157
|
+
expect(result.startsWith(prompt)).toBe(true);
|
|
158
|
+
|
|
159
|
+
// Should be longer than original prompt
|
|
160
|
+
expect(result.length).toBeGreaterThan(prompt.length);
|
|
161
|
+
|
|
162
|
+
// Should contain the original prompt exactly
|
|
163
|
+
expect(result.indexOf(prompt)).toBe(0);
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it('should handle empty prompts', () => {
|
|
167
|
+
const result = appendSharedInstructions('', INSTRUCTION_TYPES.SYSTEM);
|
|
168
|
+
|
|
169
|
+
expect(result).toBeDefined();
|
|
170
|
+
expect(typeof result).toBe('string');
|
|
171
|
+
expect(result.length).toBeGreaterThan(0);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('should handle prompts with existing content', () => {
|
|
175
|
+
const prompt = 'You are an expert software architect. Consider scalability and performance.';
|
|
176
|
+
const result = appendSharedInstructions(prompt, INSTRUCTION_TYPES.PROPOSAL);
|
|
177
|
+
|
|
178
|
+
expect(result).toBeDefined();
|
|
179
|
+
expect(typeof result).toBe('string');
|
|
180
|
+
expect(result).toContain(prompt);
|
|
181
|
+
expect(result.length).toBeGreaterThan(prompt.length);
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
describe('appendSharedInstructions() - Edge cases', () => {
|
|
186
|
+
it('should handle prompts of various lengths', () => {
|
|
187
|
+
const shortPrompt = 'Solve this.';
|
|
188
|
+
const mediumPrompt = 'You are an expert. Consider multiple factors and provide a comprehensive solution.';
|
|
189
|
+
const longPrompt = 'You are an expert software architect specializing in distributed systems and scalable architecture design. Consider scalability, performance, component boundaries, interfaces, architectural patterns, data flow, state management, and operational concerns. When proposing solutions, start with high-level architecture, identify key components, communication patterns, failure modes, and provide clear descriptions.';
|
|
190
|
+
|
|
191
|
+
const shortResult = appendSharedInstructions(shortPrompt, INSTRUCTION_TYPES.SYSTEM);
|
|
192
|
+
const mediumResult = appendSharedInstructions(mediumPrompt, INSTRUCTION_TYPES.SYSTEM);
|
|
193
|
+
const longResult = appendSharedInstructions(longPrompt, INSTRUCTION_TYPES.SYSTEM);
|
|
194
|
+
|
|
195
|
+
expect(shortResult).toContain(shortPrompt);
|
|
196
|
+
expect(mediumResult).toContain(mediumPrompt);
|
|
197
|
+
expect(longResult).toContain(longPrompt);
|
|
198
|
+
|
|
199
|
+
expect(shortResult.length).toBeGreaterThan(shortPrompt.length);
|
|
200
|
+
expect(mediumResult.length).toBeGreaterThan(mediumPrompt.length);
|
|
201
|
+
expect(longResult.length).toBeGreaterThan(longPrompt.length);
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it('should be consistent across multiple calls', () => {
|
|
205
|
+
const prompt = 'Test prompt for consistency';
|
|
206
|
+
const result1 = appendSharedInstructions(prompt, INSTRUCTION_TYPES.CRITIQUE);
|
|
207
|
+
const result2 = appendSharedInstructions(prompt, INSTRUCTION_TYPES.CRITIQUE);
|
|
208
|
+
|
|
209
|
+
expect(result1).toBe(result2);
|
|
210
|
+
});
|
|
211
|
+
|
|
212
|
+
it('should produce different results for different instruction types', () => {
|
|
213
|
+
const prompt = 'Same prompt for all types';
|
|
214
|
+
|
|
215
|
+
const systemResult = appendSharedInstructions(prompt, INSTRUCTION_TYPES.SYSTEM);
|
|
216
|
+
const proposalResult = appendSharedInstructions(prompt, INSTRUCTION_TYPES.PROPOSAL);
|
|
217
|
+
const critiqueResult = appendSharedInstructions(prompt, INSTRUCTION_TYPES.CRITIQUE);
|
|
218
|
+
const refinementResult = appendSharedInstructions(prompt, INSTRUCTION_TYPES.REFINEMENT);
|
|
219
|
+
const summarizationResult = appendSharedInstructions(prompt, INSTRUCTION_TYPES.SUMMARIZATION);
|
|
220
|
+
|
|
221
|
+
// All should contain the original prompt
|
|
222
|
+
expect(systemResult).toContain(prompt);
|
|
223
|
+
expect(proposalResult).toContain(prompt);
|
|
224
|
+
expect(critiqueResult).toContain(prompt);
|
|
225
|
+
expect(refinementResult).toContain(prompt);
|
|
226
|
+
expect(summarizationResult).toContain(prompt);
|
|
227
|
+
|
|
228
|
+
// But should be different from each other
|
|
229
|
+
expect(systemResult).not.toBe(proposalResult);
|
|
230
|
+
expect(systemResult).not.toBe(critiqueResult);
|
|
231
|
+
expect(systemResult).not.toBe(refinementResult);
|
|
232
|
+
expect(systemResult).not.toBe(summarizationResult);
|
|
233
|
+
|
|
234
|
+
expect(proposalResult).not.toBe(critiqueResult);
|
|
235
|
+
expect(proposalResult).not.toBe(refinementResult);
|
|
236
|
+
expect(proposalResult).not.toBe(summarizationResult);
|
|
237
|
+
|
|
238
|
+
expect(critiqueResult).not.toBe(refinementResult);
|
|
239
|
+
expect(critiqueResult).not.toBe(summarizationResult);
|
|
240
|
+
|
|
241
|
+
expect(refinementResult).not.toBe(summarizationResult);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it('should preserve original prompt content exactly', () => {
|
|
245
|
+
const prompt = 'Original prompt content with special characters: !@#$%^&*()';
|
|
246
|
+
const result = appendSharedInstructions(prompt, INSTRUCTION_TYPES.REFINEMENT);
|
|
247
|
+
|
|
248
|
+
// Should start with exact original prompt
|
|
249
|
+
expect(result.startsWith(prompt)).toBe(true);
|
|
250
|
+
|
|
251
|
+
// Should contain the exact original prompt at the beginning
|
|
252
|
+
expect(result.indexOf(prompt)).toBe(0);
|
|
253
|
+
});
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
describe('Integration testing', () => {
|
|
257
|
+
it('should work with realistic prompt scenarios', () => {
|
|
258
|
+
const realisticPrompt = `You are an expert software architect specializing in distributed systems and scalable architecture design.
|
|
259
|
+
Consider scalability, performance, component boundaries, interfaces, architectural patterns, data flow, state management, and operational concerns.
|
|
260
|
+
When proposing solutions, start with high-level architecture, identify key components, communication patterns, failure modes, and provide clear descriptions.
|
|
261
|
+
When critiquing, look for scalability bottlenecks, missing components, architectural coherence, and operational complexity.`;
|
|
262
|
+
|
|
263
|
+
const result = appendSharedInstructions(realisticPrompt, INSTRUCTION_TYPES.SYSTEM);
|
|
264
|
+
|
|
265
|
+
expect(result).toBeDefined();
|
|
266
|
+
expect(typeof result).toBe('string');
|
|
267
|
+
expect(result).toContain(realisticPrompt);
|
|
268
|
+
expect(result.length).toBeGreaterThan(realisticPrompt.length);
|
|
269
|
+
});
|
|
270
|
+
|
|
271
|
+
it('should maintain proper formatting', () => {
|
|
272
|
+
const multiLinePrompt = `Problem to solve:
|
|
273
|
+
Design a scalable web application
|
|
274
|
+
|
|
275
|
+
Requirements:
|
|
276
|
+
- Handle 1M+ users
|
|
277
|
+
- 99.9% uptime
|
|
278
|
+
- Global deployment`;
|
|
279
|
+
|
|
280
|
+
const result = appendSharedInstructions(multiLinePrompt, INSTRUCTION_TYPES.PROPOSAL);
|
|
281
|
+
|
|
282
|
+
expect(result).toBeDefined();
|
|
283
|
+
expect(result).toContain(multiLinePrompt);
|
|
284
|
+
expect(result.length).toBeGreaterThan(multiLinePrompt.length);
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
it('should work correctly with all instruction types in sequence', () => {
|
|
288
|
+
const basePrompt = 'Base prompt for testing';
|
|
289
|
+
|
|
290
|
+
const systemResult = appendSharedInstructions(basePrompt, INSTRUCTION_TYPES.SYSTEM);
|
|
291
|
+
const proposalResult = appendSharedInstructions(basePrompt, INSTRUCTION_TYPES.PROPOSAL);
|
|
292
|
+
const critiqueResult = appendSharedInstructions(basePrompt, INSTRUCTION_TYPES.CRITIQUE);
|
|
293
|
+
const refinementResult = appendSharedInstructions(basePrompt, INSTRUCTION_TYPES.REFINEMENT);
|
|
294
|
+
const summarizationResult = appendSharedInstructions(basePrompt, INSTRUCTION_TYPES.SUMMARIZATION);
|
|
295
|
+
|
|
296
|
+
// All should work without errors
|
|
297
|
+
expect(systemResult).toBeDefined();
|
|
298
|
+
expect(proposalResult).toBeDefined();
|
|
299
|
+
expect(critiqueResult).toBeDefined();
|
|
300
|
+
expect(refinementResult).toBeDefined();
|
|
301
|
+
expect(summarizationResult).toBeDefined();
|
|
302
|
+
|
|
303
|
+
// All should contain the base prompt
|
|
304
|
+
expect(systemResult).toContain(basePrompt);
|
|
305
|
+
expect(proposalResult).toContain(basePrompt);
|
|
306
|
+
expect(critiqueResult).toContain(basePrompt);
|
|
307
|
+
expect(refinementResult).toContain(basePrompt);
|
|
308
|
+
expect(summarizationResult).toContain(basePrompt);
|
|
309
|
+
|
|
310
|
+
// All should be longer than the base prompt
|
|
311
|
+
expect(systemResult.length).toBeGreaterThan(basePrompt.length);
|
|
312
|
+
expect(proposalResult.length).toBeGreaterThan(basePrompt.length);
|
|
313
|
+
expect(critiqueResult.length).toBeGreaterThan(basePrompt.length);
|
|
314
|
+
expect(refinementResult.length).toBeGreaterThan(basePrompt.length);
|
|
315
|
+
expect(summarizationResult.length).toBeGreaterThan(basePrompt.length);
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
});
|
|
@@ -0,0 +1,251 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import os from 'os';
|
|
4
|
+
import { StateManager } from '../src/core/state-manager';
|
|
5
|
+
import { DEBATE_STATUS, DebateSummary, SUMMARIZATION_METHODS } from '../src/types/debate.types';
|
|
6
|
+
import { AGENT_ROLES } from '../src/types/agent.types';
|
|
7
|
+
|
|
8
|
+
describe('StateManager promptSources', () => {
|
|
9
|
+
let tmpDir: string;
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'debate-state-'));
|
|
12
|
+
});
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch {}
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('persists promptSources in debate state file', async () => {
|
|
18
|
+
const sm = new StateManager(tmpDir);
|
|
19
|
+
const state = await sm.createDebate('Test Problem');
|
|
20
|
+
expect(state.status).toBe(DEBATE_STATUS.RUNNING);
|
|
21
|
+
|
|
22
|
+
await sm.setPromptSources(state.id, {
|
|
23
|
+
agents: [ { agentId: 'a1', role: 'architect', source: 'built-in' } ],
|
|
24
|
+
judge: { id: 'j1', source: 'file', path: 'C:/abs/path.md' }
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
const filePath = path.join(tmpDir, `${state.id}.json`);
|
|
28
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
29
|
+
const parsed = JSON.parse(raw);
|
|
30
|
+
expect(parsed.promptSources).toBeTruthy();
|
|
31
|
+
expect(parsed.promptSources.agents[0].agentId).toBe('a1');
|
|
32
|
+
expect(parsed.promptSources.judge.path).toContain('path.md');
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// RED-phase: state manager not implemented yet.
|
|
37
|
+
|
|
38
|
+
describe('StateManager (file-first persistence)', () => {
|
|
39
|
+
it('creates and persists a new debate on createDebate', async () => {
|
|
40
|
+
const sm = new StateManager();
|
|
41
|
+
const state = await sm.createDebate('Problem');
|
|
42
|
+
expect(state.id).toBeDefined();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it('beginRound creates a new round and increments currentRound', async () => {
|
|
46
|
+
const sm = new StateManager();
|
|
47
|
+
const state = await sm.createDebate('Problem');
|
|
48
|
+
expect(state.currentRound).toBe(0);
|
|
49
|
+
await sm.beginRound(state.id);
|
|
50
|
+
const loaded = await sm.getDebate(state.id);
|
|
51
|
+
expect(loaded?.currentRound).toBe(1);
|
|
52
|
+
expect(loaded?.rounds.length).toBe(1);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('addContribution throws if called before beginRound', async () => {
|
|
56
|
+
const sm = new StateManager();
|
|
57
|
+
const state = await sm.createDebate('Problem');
|
|
58
|
+
await expect(sm.addContribution(state.id, {
|
|
59
|
+
agentId: 'a1',
|
|
60
|
+
agentRole: 'architect' as any,
|
|
61
|
+
type: 'proposal',
|
|
62
|
+
content: 'x',
|
|
63
|
+
metadata: {},
|
|
64
|
+
})).rejects.toThrow(/No active round/);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe('StateManager - addSummary()', () => {
|
|
69
|
+
let tmpDir: string;
|
|
70
|
+
|
|
71
|
+
beforeEach(() => {
|
|
72
|
+
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'debate-summary-'));
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
afterEach(() => {
|
|
76
|
+
try { fs.rmSync(tmpDir, { recursive: true, force: true }); } catch {}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should add summary to current round', async () => {
|
|
80
|
+
const sm = new StateManager(tmpDir);
|
|
81
|
+
const state = await sm.createDebate('Test Problem');
|
|
82
|
+
await sm.beginRound(state.id);
|
|
83
|
+
|
|
84
|
+
const summary: DebateSummary = {
|
|
85
|
+
agentId: 'agent-1',
|
|
86
|
+
agentRole: AGENT_ROLES.ARCHITECT,
|
|
87
|
+
summary: 'Test summary text',
|
|
88
|
+
metadata: {
|
|
89
|
+
beforeChars: 1000,
|
|
90
|
+
afterChars: 500,
|
|
91
|
+
method: SUMMARIZATION_METHODS.LENGTH_BASED,
|
|
92
|
+
timestamp: new Date()
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
await sm.addSummary(state.id, summary);
|
|
97
|
+
|
|
98
|
+
const debate = await sm.getDebate(state.id);
|
|
99
|
+
expect(debate).toBeDefined();
|
|
100
|
+
expect(debate!.rounds.length).toBe(1);
|
|
101
|
+
const round = debate!.rounds[0];
|
|
102
|
+
expect(round).toBeDefined();
|
|
103
|
+
expect(round!.summaries).toBeDefined();
|
|
104
|
+
expect(Object.keys(round!.summaries!).length).toBe(1);
|
|
105
|
+
expect(round!.summaries!['agent-1']).toEqual(summary);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it('should initialize summaries array if not present', async () => {
|
|
109
|
+
const sm = new StateManager(tmpDir);
|
|
110
|
+
const state = await sm.createDebate('Test Problem');
|
|
111
|
+
await sm.beginRound(state.id);
|
|
112
|
+
|
|
113
|
+
// First summary should initialize the array
|
|
114
|
+
const summary1: DebateSummary = {
|
|
115
|
+
agentId: 'agent-1',
|
|
116
|
+
agentRole: AGENT_ROLES.ARCHITECT,
|
|
117
|
+
summary: 'First summary',
|
|
118
|
+
metadata: {
|
|
119
|
+
beforeChars: 1000,
|
|
120
|
+
afterChars: 500,
|
|
121
|
+
method: SUMMARIZATION_METHODS.LENGTH_BASED,
|
|
122
|
+
timestamp: new Date()
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
await sm.addSummary(state.id, summary1);
|
|
127
|
+
|
|
128
|
+
const debate = await sm.getDebate(state.id);
|
|
129
|
+
const round = debate!.rounds[0];
|
|
130
|
+
expect(round).toBeDefined();
|
|
131
|
+
expect(round!.summaries).toBeDefined();
|
|
132
|
+
expect(round!.summaries!['agent-1']).toBeDefined();
|
|
133
|
+
expect(round!.summaries!['agent-1']!.agentId).toBe('agent-1');
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
it('should support multiple summaries per round', async () => {
|
|
137
|
+
const sm = new StateManager(tmpDir);
|
|
138
|
+
const state = await sm.createDebate('Test Problem');
|
|
139
|
+
await sm.beginRound(state.id);
|
|
140
|
+
|
|
141
|
+
const summary1: DebateSummary = {
|
|
142
|
+
agentId: 'agent-1',
|
|
143
|
+
agentRole: AGENT_ROLES.ARCHITECT,
|
|
144
|
+
summary: 'Summary 1',
|
|
145
|
+
metadata: {
|
|
146
|
+
beforeChars: 1000,
|
|
147
|
+
afterChars: 500,
|
|
148
|
+
method: SUMMARIZATION_METHODS.LENGTH_BASED,
|
|
149
|
+
timestamp: new Date()
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
const summary2: DebateSummary = {
|
|
154
|
+
agentId: 'agent-2',
|
|
155
|
+
agentRole: AGENT_ROLES.PERFORMANCE,
|
|
156
|
+
summary: 'Summary 2',
|
|
157
|
+
metadata: {
|
|
158
|
+
beforeChars: 2000,
|
|
159
|
+
afterChars: 1000,
|
|
160
|
+
method: SUMMARIZATION_METHODS.LENGTH_BASED,
|
|
161
|
+
timestamp: new Date()
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
await sm.addSummary(state.id, summary1);
|
|
166
|
+
await sm.addSummary(state.id, summary2);
|
|
167
|
+
|
|
168
|
+
const debate = await sm.getDebate(state.id);
|
|
169
|
+
const round = debate!.rounds[0];
|
|
170
|
+
expect(round).toBeDefined();
|
|
171
|
+
expect(Object.keys(round!.summaries!).length).toBe(2);
|
|
172
|
+
const summaries = round!.summaries;
|
|
173
|
+
if (summaries) {
|
|
174
|
+
expect(summaries['agent-1']).toBeDefined();
|
|
175
|
+
expect(summaries['agent-2']).toBeDefined();
|
|
176
|
+
expect(summaries['agent-1']!.agentId).toBe('agent-1');
|
|
177
|
+
expect(summaries['agent-2']!.agentId).toBe('agent-2');
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
it('should persist summaries to disk', async () => {
|
|
182
|
+
const sm = new StateManager(tmpDir);
|
|
183
|
+
const state = await sm.createDebate('Test Problem');
|
|
184
|
+
await sm.beginRound(state.id);
|
|
185
|
+
|
|
186
|
+
const summary: DebateSummary = {
|
|
187
|
+
agentId: 'agent-1',
|
|
188
|
+
agentRole: AGENT_ROLES.ARCHITECT,
|
|
189
|
+
summary: 'Persisted summary',
|
|
190
|
+
metadata: {
|
|
191
|
+
beforeChars: 1500,
|
|
192
|
+
afterChars: 750,
|
|
193
|
+
method: SUMMARIZATION_METHODS.LENGTH_BASED,
|
|
194
|
+
timestamp: new Date(),
|
|
195
|
+
latencyMs: 200,
|
|
196
|
+
tokensUsed: 50
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
await sm.addSummary(state.id, summary);
|
|
201
|
+
|
|
202
|
+
// Read directly from file to verify persistence
|
|
203
|
+
const filePath = path.join(tmpDir, `${state.id}.json`);
|
|
204
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
205
|
+
const parsed = JSON.parse(raw);
|
|
206
|
+
|
|
207
|
+
expect(parsed.rounds[0].summaries).toBeDefined();
|
|
208
|
+
expect(Object.keys(parsed.rounds[0].summaries).length).toBe(1);
|
|
209
|
+
expect(parsed.rounds[0].summaries['agent-1']).toBeDefined();
|
|
210
|
+
expect(parsed.rounds[0].summaries['agent-1'].summary).toBe('Persisted summary');
|
|
211
|
+
expect(parsed.rounds[0].summaries['agent-1'].metadata.latencyMs).toBe(200);
|
|
212
|
+
expect(parsed.rounds[0].summaries['agent-1'].metadata.tokensUsed).toBe(50);
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it('should throw error if no active round', async () => {
|
|
216
|
+
const sm = new StateManager(tmpDir);
|
|
217
|
+
const state = await sm.createDebate('Test Problem');
|
|
218
|
+
|
|
219
|
+
const summary: DebateSummary = {
|
|
220
|
+
agentId: 'agent-1',
|
|
221
|
+
agentRole: AGENT_ROLES.ARCHITECT,
|
|
222
|
+
summary: 'Test summary',
|
|
223
|
+
metadata: {
|
|
224
|
+
beforeChars: 1000,
|
|
225
|
+
afterChars: 500,
|
|
226
|
+
method: SUMMARIZATION_METHODS.LENGTH_BASED,
|
|
227
|
+
timestamp: new Date()
|
|
228
|
+
}
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
await expect(sm.addSummary(state.id, summary)).rejects.toThrow(/No active round/);
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('should throw error if debate not found', async () => {
|
|
235
|
+
const sm = new StateManager(tmpDir);
|
|
236
|
+
|
|
237
|
+
const summary: DebateSummary = {
|
|
238
|
+
agentId: 'agent-1',
|
|
239
|
+
agentRole: AGENT_ROLES.ARCHITECT,
|
|
240
|
+
summary: 'Test summary',
|
|
241
|
+
metadata: {
|
|
242
|
+
beforeChars: 1000,
|
|
243
|
+
afterChars: 500,
|
|
244
|
+
method: SUMMARIZATION_METHODS.LENGTH_BASED,
|
|
245
|
+
timestamp: new Date()
|
|
246
|
+
}
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
await expect(sm.addSummary('nonexistent-id', summary)).rejects.toThrow(/not found/);
|
|
250
|
+
});
|
|
251
|
+
});
|