Skip to content

Commit 7da290d

Browse files
committed
refactor(reflexion): update createMockRunner and test configurations for improved readability
1 parent d757d90 commit 7da290d

2 files changed

Lines changed: 113 additions & 16 deletions

File tree

src/lib/ai/reflexion/__tests__/engine.test.ts

Lines changed: 112 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,29 @@
1-
import { runReflexion, resumeReflexion, ReflexionRunner, ReflexionConfig } from '../engine';
2-
import { ReflexionStateV2, Answers } from '../schema';
1+
import {
2+
ReflexionConfig,
3+
ReflexionRunner,
4+
resumeReflexion,
5+
runReflexion,
6+
} from '../engine';
7+
import { Answers, ReflexionStateV2 } from '../schema';
38

49
function createMockRunner(
510
generateResponse = 'plan',
6-
critiqueResponse = { passed: true, score: 9, actionableFix: '', gstackDiagnosis: 9, atomicBatches: 9, productionEthos: 9, modernWeb: 9 },
11+
critiqueResponse = {
12+
passed: true,
13+
score: 9,
14+
actionableFix: '',
15+
gstackDiagnosis: 9,
16+
atomicBatches: 9,
17+
productionEthos: 9,
18+
modernWeb: 9,
19+
},
720
adjudicateResponse = 'verdict',
8-
interviewResponse: any = { runId: '123', revision: 0, recommendation: 'approve', questions: [] },
21+
interviewResponse: any = {
22+
runId: '123',
23+
revision: 0,
24+
recommendation: 'approve',
25+
questions: [],
26+
},
927
usageResponse = { tokens: 10, costUsd: 0.1 }
1028
): ReflexionRunner {
1129
return {
@@ -14,6 +32,7 @@ function createMockRunner(
1432
adjudicate: jest.fn().mockResolvedValue(adjudicateResponse),
1533
interview: jest.fn().mockResolvedValue(interviewResponse),
1634
getUsage: jest.fn().mockReturnValue(usageResponse),
35+
wasDegraded: jest.fn(() => false),
1736
models: { creator: 'gemini', critic: 'claude', adjudicator: 'claude' },
1837
};
1938
}
@@ -36,41 +55,108 @@ describe('engine v2', () => {
3655
});
3756

3857
it('budget gate trips', async () => {
39-
const runner = createMockRunner('plan', undefined, undefined, undefined, { tokens: 1000, costUsd: 10 });
40-
const cfg: ReflexionConfig = { brief: 'test', mode: 'auto', budget: { maxCostUsd: 1 } };
58+
const runner = createMockRunner('plan', undefined, undefined, undefined, {
59+
tokens: 1000,
60+
costUsd: 10,
61+
});
62+
const cfg: ReflexionConfig = {
63+
brief: 'test',
64+
mode: 'auto',
65+
budget: { maxCostUsd: 1 },
66+
};
4167
const res = await runReflexion(runner, cfg);
4268
expect(res.stopReason).toBe('budget-exceeded');
4369
expect(runner.generate).not.toHaveBeenCalled();
4470
});
4571

4672
it('zero-question auto-approve', async () => {
47-
const runner = createMockRunner('plan', { passed: false, score: 8, actionableFix: 'fix', gstackDiagnosis: 9, atomicBatches: 9, productionEthos: 9, modernWeb: 9 }, 'verdict', { runId: '1', revision: 0, recommendation: 'refine-plan', questions: [{ id: '1', target: 'plan', ref: '## P0', question: 'q', why: 'w' }] });
48-
const cfg: ReflexionConfig = { brief: 'test', mode: 'interview', passThreshold: 8 };
73+
const runner = createMockRunner(
74+
'plan',
75+
{
76+
passed: false,
77+
score: 8,
78+
actionableFix: 'fix',
79+
gstackDiagnosis: 9,
80+
atomicBatches: 9,
81+
productionEthos: 9,
82+
modernWeb: 9,
83+
},
84+
'verdict',
85+
{
86+
runId: '1',
87+
revision: 0,
88+
recommendation: 'refine-plan',
89+
questions: [
90+
{ id: '1', target: 'plan', ref: '## P0', question: 'q', why: 'w' },
91+
],
92+
}
93+
);
94+
const cfg: ReflexionConfig = {
95+
brief: 'test',
96+
mode: 'interview',
97+
passThreshold: 8,
98+
};
4999
const res = await runReflexion(runner, cfg);
50100
expect(res.interview?.recommendation).toBe('approve');
51101
expect(res.interview?.questions).toHaveLength(0);
52102
expect(res.stopReason).toBe('passed');
53103
});
54104

55105
it('resume refine-plan updates params', async () => {
56-
const runner = createMockRunner('plan', { passed: true, score: 9, actionableFix: '', gstackDiagnosis: 9, atomicBatches: 9, productionEthos: 9, modernWeb: 9 }, 'verdict', { runId: '123', revision: 1, recommendation: 'approve', questions: [] });
106+
const runner = createMockRunner(
107+
'plan',
108+
{
109+
passed: true,
110+
score: 9,
111+
actionableFix: '',
112+
gstackDiagnosis: 9,
113+
atomicBatches: 9,
114+
productionEthos: 9,
115+
modernWeb: 9,
116+
},
117+
'verdict',
118+
{ runId: '123', revision: 1, recommendation: 'approve', questions: [] }
119+
);
57120
const state: ReflexionStateV2 = {
58121
version: 2,
59122
runId: '123',
60123
brief: 'b',
61124
phase: 'AWAITING_ANSWERS',
62125
plan: 'old plan',
63-
critiques: [{ passed: true, score: 9, actionableFix: '', gstackDiagnosis: 9, atomicBatches: 9, productionEthos: 9, modernWeb: 9 }],
126+
critiques: [
127+
{
128+
passed: true,
129+
score: 9,
130+
actionableFix: '',
131+
gstackDiagnosis: 9,
132+
atomicBatches: 9,
133+
productionEthos: 9,
134+
modernWeb: 9,
135+
},
136+
],
64137
revision: 1,
65138
params: { passThreshold: 8, maxRevisions: 3 },
66139
usage: { totalTokens: 0, costUsd: 0, perPhase: [] },
67140
createdAt: 'd',
68141
updatedAt: 'd',
69-
interview: { runId: '123', revision: 0, recommendation: 'tune-loop', questions: [{ id: 'q1', target: 'loop', ref: 'passThreshold', question: '?', why: '!' }] }
142+
interview: {
143+
runId: '123',
144+
revision: 0,
145+
recommendation: 'tune-loop',
146+
questions: [
147+
{
148+
id: 'q1',
149+
target: 'loop',
150+
ref: 'passThreshold',
151+
question: '?',
152+
why: '!',
153+
},
154+
],
155+
},
70156
};
71157
const answers: Answers = {
72158
runId: '123',
73-
decisions: [{ id: 'q1', answer: '9' }]
159+
decisions: [{ id: 'q1', answer: '9' }],
74160
};
75161
const cfg: ReflexionConfig = { brief: 'b', mode: 'auto' };
76162
const res = await resumeReflexion(runner, state, answers, cfg);
@@ -92,11 +178,18 @@ describe('engine v2', () => {
92178
usage: { totalTokens: 0, costUsd: 0, perPhase: [] },
93179
createdAt: 'd',
94180
updatedAt: 'd',
95-
interview: { runId: '123', revision: 0, recommendation: 'refine-plan', questions: [{ id: 'q1', target: 'plan', ref: '## P0', question: '?', why: '!' }] }
181+
interview: {
182+
runId: '123',
183+
revision: 0,
184+
recommendation: 'refine-plan',
185+
questions: [
186+
{ id: 'q1', target: 'plan', ref: '## P0', question: '?', why: '!' },
187+
],
188+
},
96189
};
97190
const answers: Answers = {
98191
runId: '123',
99-
decisions: [{ id: 'q1', answer: 'change this' }]
192+
decisions: [{ id: 'q1', answer: 'change this' }],
100193
};
101194
const cfg: ReflexionConfig = { brief: 'b' };
102195
const res = await resumeReflexion(runner, state, answers, cfg);
@@ -109,7 +202,11 @@ describe('engine v2', () => {
109202
load: jest.fn(),
110203
save: jest.fn().mockResolvedValue(undefined),
111204
};
112-
const cfg: ReflexionConfig = { brief: 'test', mode: 'auto', stateStore: mockStore };
205+
const cfg: ReflexionConfig = {
206+
brief: 'test',
207+
mode: 'auto',
208+
stateStore: mockStore,
209+
};
113210
await runReflexion(runner, cfg);
114211
expect(mockStore.save).toHaveBeenCalled();
115212
});

src/lib/ai/reflexion/schema.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ export const ReflexionStateV2Schema = z.object({
113113
stopReason: StopReasonSchema.optional(),
114114
createdAt: z.string(),
115115
updatedAt: z.string(),
116-
criticDegraded: z.boolean().default(false),
116+
criticDegraded: z.boolean().default(false).optional(),
117117
});
118118
export type ReflexionStateV2 = z.infer<typeof ReflexionStateV2Schema>;
119119

0 commit comments

Comments
 (0)