@principles/core 1.147.0 → 1.149.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/dist/runtime-v2/__tests__/architecture-regression.test.js +5 -0
- package/dist/runtime-v2/__tests__/architecture-regression.test.js.map +1 -1
- package/dist/runtime-v2/adapter/__tests__/l2-agent-loop-adapter.test.d.ts +2 -0
- package/dist/runtime-v2/adapter/__tests__/l2-agent-loop-adapter.test.d.ts.map +1 -0
- package/dist/runtime-v2/adapter/__tests__/l2-agent-loop-adapter.test.js +420 -0
- package/dist/runtime-v2/adapter/__tests__/l2-agent-loop-adapter.test.js.map +1 -0
- package/dist/runtime-v2/adapter/l2-agent-loop-adapter.d.ts +70 -0
- package/dist/runtime-v2/adapter/l2-agent-loop-adapter.d.ts.map +1 -0
- package/dist/runtime-v2/adapter/l2-agent-loop-adapter.js +478 -0
- package/dist/runtime-v2/adapter/l2-agent-loop-adapter.js.map +1 -0
- package/dist/runtime-v2/agent-spec.d.ts +1 -1
- package/dist/runtime-v2/feature-flags/feature-flag-contract.d.ts.map +1 -1
- package/dist/runtime-v2/feature-flags/feature-flag-contract.js +5 -0
- package/dist/runtime-v2/feature-flags/feature-flag-contract.js.map +1 -1
- package/dist/runtime-v2/index.d.ts +5 -0
- package/dist/runtime-v2/index.d.ts.map +1 -1
- package/dist/runtime-v2/index.js +5 -0
- package/dist/runtime-v2/index.js.map +1 -1
- package/dist/runtime-v2/runtime-protocol.d.ts +3 -3
- package/dist/runtime-v2/runtime-protocol.d.ts.map +1 -1
- package/dist/runtime-v2/runtime-protocol.js +1 -0
- package/dist/runtime-v2/runtime-protocol.js.map +1 -1
- package/dist/runtime-v2/runtime-selector.d.ts +3 -3
- package/dist/runtime-v2/tools/__tests__/agent-tool-contract.test.d.ts +2 -0
- package/dist/runtime-v2/tools/__tests__/agent-tool-contract.test.d.ts.map +1 -0
- package/dist/runtime-v2/tools/__tests__/agent-tool-contract.test.js +171 -0
- package/dist/runtime-v2/tools/__tests__/agent-tool-contract.test.js.map +1 -0
- package/dist/runtime-v2/tools/__tests__/dreamer-output-typebox.test.d.ts +2 -0
- package/dist/runtime-v2/tools/__tests__/dreamer-output-typebox.test.d.ts.map +1 -0
- package/dist/runtime-v2/tools/__tests__/dreamer-output-typebox.test.js +109 -0
- package/dist/runtime-v2/tools/__tests__/dreamer-output-typebox.test.js.map +1 -0
- package/dist/runtime-v2/tools/agent-tool-contract.d.ts +76 -0
- package/dist/runtime-v2/tools/agent-tool-contract.d.ts.map +1 -0
- package/dist/runtime-v2/tools/agent-tool-contract.js +136 -0
- package/dist/runtime-v2/tools/agent-tool-contract.js.map +1 -0
- package/dist/runtime-v2/tools/dreamer-output-typebox.d.ts +63 -0
- package/dist/runtime-v2/tools/dreamer-output-typebox.d.ts.map +1 -0
- package/dist/runtime-v2/tools/dreamer-output-typebox.js +55 -0
- package/dist/runtime-v2/tools/dreamer-output-typebox.js.map +1 -0
- package/dist/telemetry-event.d.ts +3 -3
- package/dist/telemetry-event.d.ts.map +1 -1
- package/dist/telemetry-event.js +8 -1
- package/dist/telemetry-event.js.map +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"l2-agent-loop-adapter.test.d.ts","sourceRoot":"","sources":["../../../../src/runtime-v2/adapter/__tests__/l2-agent-loop-adapter.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PRI-419 §M3 — L2AgentLoopAdapter integration tests.
|
|
3
|
+
*
|
|
4
|
+
* Mocks runAgentLoop (no real LLM calls) to verify the adapter's orchestration:
|
|
5
|
+
* - submit_output capture terminates the loop (primary extraction)
|
|
6
|
+
* - maxTurns cap forces stop when submit_output is never called
|
|
7
|
+
* - fallback extraction from the last text-bearing assistant message
|
|
8
|
+
* - beforeToolCall whitelist blocks non-allowlisted tools
|
|
9
|
+
* - telemetry events (dreamer_l2_turn / dreamer_l2_complete) are emitted
|
|
10
|
+
* - output goes through the same shape as L1 (StructuredRunOutput)
|
|
11
|
+
*/
|
|
12
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
13
|
+
const hoisted = vi.hoisted(() => {
|
|
14
|
+
return {
|
|
15
|
+
lastLoopConfig: {},
|
|
16
|
+
mockReturn: [],
|
|
17
|
+
impl: null,
|
|
18
|
+
};
|
|
19
|
+
});
|
|
20
|
+
/* eslint-disable @typescript-eslint/max-params -- runAgentLoop mock mirrors the real 5-param signature */
|
|
21
|
+
// Mock runAgentLoop — the adapter's only entry into pi-agent-core.
|
|
22
|
+
vi.mock('@earendil-works/pi-agent-core', () => ({
|
|
23
|
+
runAgentLoop: vi.fn(async (prompts, context, config, emit, signal) => {
|
|
24
|
+
hoisted.lastLoopConfig = config;
|
|
25
|
+
// Per-test override via mockImplementation takes precedence; otherwise return the staged transcript.
|
|
26
|
+
if (typeof hoisted.impl === 'function') {
|
|
27
|
+
const fn = hoisted.impl;
|
|
28
|
+
return fn(prompts, context, config, emit, signal);
|
|
29
|
+
}
|
|
30
|
+
return hoisted.mockReturn.slice();
|
|
31
|
+
}),
|
|
32
|
+
}));
|
|
33
|
+
/* eslint-enable @typescript-eslint/max-params */
|
|
34
|
+
// PRI-420: mock completeSimple for L1 fallback tests. getModel/getProviders are used by resolveL2Model
|
|
35
|
+
// in all tests (via the custom baseUrl path), so provide stubs.
|
|
36
|
+
vi.mock('@earendil-works/pi-ai', () => ({
|
|
37
|
+
completeSimple: vi.fn(),
|
|
38
|
+
getModel: vi.fn(() => ({ id: 'test', name: 'test', api: 'openai-completions', provider: 'test-provider' })),
|
|
39
|
+
getProviders: vi.fn(() => []),
|
|
40
|
+
}));
|
|
41
|
+
// Mock store/event-emitter to capture telemetry.
|
|
42
|
+
vi.mock('../../store/event-emitter.js', () => ({
|
|
43
|
+
storeEmitter: { emitTelemetry: vi.fn() },
|
|
44
|
+
}));
|
|
45
|
+
import { storeEmitter } from '../../store/event-emitter.js';
|
|
46
|
+
import { completeSimple } from '@earendil-works/pi-ai';
|
|
47
|
+
import { L2AgentLoopAdapter } from '../l2-agent-loop-adapter.js';
|
|
48
|
+
const emitTelemetryMock = storeEmitter.emitTelemetry;
|
|
49
|
+
const mockComplete = completeSimple;
|
|
50
|
+
// Minimal fakes for the injected readers.
|
|
51
|
+
const artifactReader = {
|
|
52
|
+
getArtifactById: async () => null,
|
|
53
|
+
listBySourceTaskId: async () => [],
|
|
54
|
+
};
|
|
55
|
+
const principleReader = {
|
|
56
|
+
listActivePrinciples: async () => [],
|
|
57
|
+
};
|
|
58
|
+
const VALID_DREAMER_OUTPUT = {
|
|
59
|
+
valid: true,
|
|
60
|
+
taskId: 'task-dreamer-1',
|
|
61
|
+
candidates: [
|
|
62
|
+
{ candidateIndex: 0, badDecision: 'x', betterDecision: 'y', rationale: 'r', confidence: 0.5, riskLevel: 'low', strategicPerspective: 's' },
|
|
63
|
+
],
|
|
64
|
+
contextRefs: ['ref-1'],
|
|
65
|
+
generatedAt: '2026-06-16T00:00:00.000Z',
|
|
66
|
+
};
|
|
67
|
+
function makeStartRun(overrides = {}) {
|
|
68
|
+
return {
|
|
69
|
+
agentSpec: { agentId: 'dreamer', schemaVersion: 'v1' },
|
|
70
|
+
taskRef: { taskId: 'task-dreamer-1' },
|
|
71
|
+
inputPayload: '{"prompt":"generate candidates"}',
|
|
72
|
+
contextItems: [],
|
|
73
|
+
outputSchemaRef: 'dreamer-output-v1',
|
|
74
|
+
timeoutMs: 300000,
|
|
75
|
+
...overrides,
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
function makeAdapter(overrides = {}) {
|
|
79
|
+
return new L2AgentLoopAdapter({
|
|
80
|
+
// Custom baseUrl so resolveL2Model builds the model inline (no getModel lookup).
|
|
81
|
+
provider: 'test-provider',
|
|
82
|
+
model: 'test-model',
|
|
83
|
+
apiKeyEnv: 'TEST_API_KEY',
|
|
84
|
+
baseUrl: 'http://localhost:1234/v1',
|
|
85
|
+
maxTurns: overrides.maxTurns,
|
|
86
|
+
maxEmptyRetries: overrides.maxEmptyRetries,
|
|
87
|
+
l2FallbackToL1: overrides.l2FallbackToL1,
|
|
88
|
+
totalBudgetMs: overrides.totalBudgetMs ?? 60_000,
|
|
89
|
+
}, { artifactReader, principleReader });
|
|
90
|
+
}
|
|
91
|
+
beforeEach(() => {
|
|
92
|
+
vi.clearAllMocks();
|
|
93
|
+
hoisted.mockReturn = [];
|
|
94
|
+
hoisted.impl = null;
|
|
95
|
+
hoisted.lastLoopConfig = {};
|
|
96
|
+
process.env.TEST_API_KEY = 'test-key';
|
|
97
|
+
});
|
|
98
|
+
describe('PRI-419 L2AgentLoopAdapter — submit_output capture (primary extraction)', () => {
|
|
99
|
+
it('returns the captured output when submit_output was called', async () => {
|
|
100
|
+
const adapter = makeAdapter();
|
|
101
|
+
// Simulate: the tool factory's submit_output execute() writes to outputCapture.
|
|
102
|
+
// The adapter reads outputCapture.output after the loop. We can't directly set the
|
|
103
|
+
// capture from here, so we verify via the shouldStopAfterTurn hook: after the loop
|
|
104
|
+
// returns, the adapter checks outputCapture. To exercise the capture path, we make
|
|
105
|
+
// runAgentLoop invoke the built tools' submit_output before returning.
|
|
106
|
+
hoisted.impl = async (_p, context) => {
|
|
107
|
+
const submit = context.tools?.find(t => t.name === 'submit_output');
|
|
108
|
+
if (submit) {
|
|
109
|
+
await submit.execute('call-1', VALID_DREAMER_OUTPUT);
|
|
110
|
+
}
|
|
111
|
+
return [];
|
|
112
|
+
};
|
|
113
|
+
const handle = await adapter.startRun(makeStartRun());
|
|
114
|
+
const output = await adapter.fetchOutput(handle.runId);
|
|
115
|
+
expect(output).not.toBeNull();
|
|
116
|
+
expect(output?.payload).toEqual(VALID_DREAMER_OUTPUT);
|
|
117
|
+
});
|
|
118
|
+
it('shouldStopAfterTurn returns true after output is captured', async () => {
|
|
119
|
+
const adapter = makeAdapter({ maxTurns: 5 });
|
|
120
|
+
hoisted.impl = async (_p, context) => {
|
|
121
|
+
const submit = context.tools?.find(t => t.name === 'submit_output');
|
|
122
|
+
if (submit) {
|
|
123
|
+
await submit.execute('call-1', VALID_DREAMER_OUTPUT);
|
|
124
|
+
}
|
|
125
|
+
return [];
|
|
126
|
+
};
|
|
127
|
+
await adapter.startRun(makeStartRun());
|
|
128
|
+
const stopFn = hoisted.lastLoopConfig.shouldStopAfterTurn;
|
|
129
|
+
expect(typeof stopFn).toBe('function');
|
|
130
|
+
if (!stopFn)
|
|
131
|
+
return;
|
|
132
|
+
// After submit_output captured output, the next shouldStopAfterTurn call returns true.
|
|
133
|
+
expect(stopFn()).toBe(true);
|
|
134
|
+
});
|
|
135
|
+
});
|
|
136
|
+
describe('PRI-419 L2AgentLoopAdapter — maxTurns cap', () => {
|
|
137
|
+
it('shouldStopAfterTurn returns false below maxTurns and true at/above, WITHOUT submit_output', async () => {
|
|
138
|
+
// Verifies the turn-cap path INDEPENDENTLY of output capture: submit_output is NOT
|
|
139
|
+
// called, so stopping is driven purely by turnCount reaching maxTurns. Fallback
|
|
140
|
+
// extraction (assistant message contains JSON) lets startRun succeed.
|
|
141
|
+
// The mocked runAgentLoop does NOT call shouldStopAfterTurn, so turnCount starts at 0.
|
|
142
|
+
// With maxTurns=5: calls 1-4 (turns 1-4, < 5) → false; call 5 (turn 5, >= 5) → true.
|
|
143
|
+
const adapter = makeAdapter({ maxTurns: 5 });
|
|
144
|
+
hoisted.mockReturn = [
|
|
145
|
+
{ role: 'assistant', content: JSON.stringify(VALID_DREAMER_OUTPUT) },
|
|
146
|
+
];
|
|
147
|
+
await adapter.startRun(makeStartRun());
|
|
148
|
+
const stopFn = hoisted.lastLoopConfig.shouldStopAfterTurn;
|
|
149
|
+
if (!stopFn) {
|
|
150
|
+
expect.fail('shouldStopAfterTurn not wired');
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
expect(stopFn()).toBe(false); // turn 1
|
|
154
|
+
expect(stopFn()).toBe(false); // turn 2
|
|
155
|
+
expect(stopFn()).toBe(false); // turn 3
|
|
156
|
+
expect(stopFn()).toBe(false); // turn 4
|
|
157
|
+
expect(stopFn()).toBe(true); // turn 5 (>= maxTurns)
|
|
158
|
+
expect(stopFn()).toBe(true); // turn 6 (still >= maxTurns)
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
describe('PRI-419 L2AgentLoopAdapter — fallback extraction', () => {
|
|
162
|
+
it('extracts JSON from the last assistant text message when submit_output was not called', async () => {
|
|
163
|
+
const adapter = makeAdapter();
|
|
164
|
+
hoisted.mockReturn = [
|
|
165
|
+
{ role: 'assistant', content: 'Let me check the principles first.' },
|
|
166
|
+
{ role: 'assistant', content: `Here is my output:\n${JSON.stringify(VALID_DREAMER_OUTPUT)}` },
|
|
167
|
+
];
|
|
168
|
+
const handle = await adapter.startRun(makeStartRun());
|
|
169
|
+
const output = await adapter.fetchOutput(handle.runId);
|
|
170
|
+
expect(output).not.toBeNull();
|
|
171
|
+
expect(output?.payload).toEqual(VALID_DREAMER_OUTPUT);
|
|
172
|
+
});
|
|
173
|
+
it('fails loud (output_invalid) when no submit_output and no parseable JSON', async () => {
|
|
174
|
+
const adapter = makeAdapter();
|
|
175
|
+
hoisted.mockReturn = [
|
|
176
|
+
{ role: 'assistant', content: 'I could not produce an answer.' },
|
|
177
|
+
];
|
|
178
|
+
await expect(adapter.startRun(makeStartRun())).rejects.toThrow(/no parseable JSON|submit_output was not called/);
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
describe('PRI-419 L2AgentLoopAdapter — beforeToolCall whitelist', () => {
|
|
182
|
+
it('blocks a tool not in the dreamer L2 whitelist', async () => {
|
|
183
|
+
const adapter = makeAdapter();
|
|
184
|
+
hoisted.impl = async (_p, context) => {
|
|
185
|
+
const submit = context.tools?.find(t => t.name === 'submit_output');
|
|
186
|
+
if (submit)
|
|
187
|
+
await submit.execute('call-1', VALID_DREAMER_OUTPUT);
|
|
188
|
+
return [];
|
|
189
|
+
};
|
|
190
|
+
await adapter.startRun(makeStartRun());
|
|
191
|
+
const { beforeToolCall } = hoisted.lastLoopConfig;
|
|
192
|
+
expect(typeof beforeToolCall).toBe('function');
|
|
193
|
+
if (!beforeToolCall)
|
|
194
|
+
return;
|
|
195
|
+
const result = await beforeToolCall({ toolCall: { name: 'write_file' } });
|
|
196
|
+
expect(result).toEqual({ block: true, reason: expect.stringContaining('write_file') });
|
|
197
|
+
});
|
|
198
|
+
it('allows a whitelisted tool', async () => {
|
|
199
|
+
const adapter = makeAdapter();
|
|
200
|
+
hoisted.impl = async (_p, context) => {
|
|
201
|
+
const submit = context.tools?.find(t => t.name === 'submit_output');
|
|
202
|
+
if (submit)
|
|
203
|
+
await submit.execute('call-1', VALID_DREAMER_OUTPUT);
|
|
204
|
+
return [];
|
|
205
|
+
};
|
|
206
|
+
await adapter.startRun(makeStartRun());
|
|
207
|
+
const { beforeToolCall } = hoisted.lastLoopConfig;
|
|
208
|
+
if (!beforeToolCall)
|
|
209
|
+
return;
|
|
210
|
+
const result = await beforeToolCall({ toolCall: { name: 'read_principles' } });
|
|
211
|
+
expect(result).toBeUndefined();
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
describe('PRI-419 L2AgentLoopAdapter — telemetry', () => {
|
|
215
|
+
it('emits dreamer_l2_complete on success with turnCount, toolsInvoked, usedFallback', async () => {
|
|
216
|
+
const adapter = makeAdapter();
|
|
217
|
+
hoisted.impl = async (_p, context) => {
|
|
218
|
+
const submit = context.tools?.find(t => t.name === 'submit_output');
|
|
219
|
+
if (submit)
|
|
220
|
+
await submit.execute('call-1', VALID_DREAMER_OUTPUT);
|
|
221
|
+
return [];
|
|
222
|
+
};
|
|
223
|
+
await adapter.startRun(makeStartRun());
|
|
224
|
+
const completeCalls = emitTelemetryMock.mock.calls.filter(c => c[0]?.eventType === 'dreamer_l2_complete');
|
|
225
|
+
expect(completeCalls.length).toBe(1);
|
|
226
|
+
const payload = completeCalls[0]?.[0]?.payload;
|
|
227
|
+
expect(payload).toHaveProperty('turnCount');
|
|
228
|
+
expect(payload).toHaveProperty('toolsInvoked');
|
|
229
|
+
expect(payload.usedFallback).toBe(false);
|
|
230
|
+
expect(payload.timedOut).toBe(false);
|
|
231
|
+
});
|
|
232
|
+
it('emits dreamer_l2_turn for each tool execution', async () => {
|
|
233
|
+
const adapter = makeAdapter();
|
|
234
|
+
hoisted.impl = async (_p, context) => {
|
|
235
|
+
const readPrinciples = context.tools?.find(t => t.name === 'read_principles');
|
|
236
|
+
const submit = context.tools?.find(t => t.name === 'submit_output');
|
|
237
|
+
if (readPrinciples)
|
|
238
|
+
await readPrinciples.execute('c1', {});
|
|
239
|
+
if (submit)
|
|
240
|
+
await submit.execute('c2', VALID_DREAMER_OUTPUT);
|
|
241
|
+
return [];
|
|
242
|
+
};
|
|
243
|
+
await adapter.startRun(makeStartRun());
|
|
244
|
+
const turnCalls = emitTelemetryMock.mock.calls.filter(c => c[0]?.eventType === 'dreamer_l2_turn' && c[0]?.payload?.toolName);
|
|
245
|
+
expect(turnCalls.length).toBeGreaterThanOrEqual(2);
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
describe('PRI-419 L2AgentLoopAdapter — error paths', () => {
|
|
249
|
+
it('throws runtime_unavailable when the API key env is missing', async () => {
|
|
250
|
+
delete process.env.TEST_API_KEY;
|
|
251
|
+
const adapter = makeAdapter();
|
|
252
|
+
await expect(adapter.startRun(makeStartRun())).rejects.toThrow(/API key not found/);
|
|
253
|
+
});
|
|
254
|
+
it('kind() returns pi-ai-l2', async () => {
|
|
255
|
+
const adapter = makeAdapter();
|
|
256
|
+
expect(adapter.kind()).toBe('pi-ai-l2');
|
|
257
|
+
});
|
|
258
|
+
it('getCapabilities reports supportsToolUse=true', async () => {
|
|
259
|
+
const adapter = makeAdapter();
|
|
260
|
+
const caps = await adapter.getCapabilities();
|
|
261
|
+
expect(caps.supportsToolUse).toBe(true);
|
|
262
|
+
});
|
|
263
|
+
});
|
|
264
|
+
describe('PRI-419 L2AgentLoopAdapter — fallback edge cases (P2-3)', () => {
|
|
265
|
+
it('returns null (fail loud) when the last assistant message has content: null', async () => {
|
|
266
|
+
// content: null is neither string nor array; extraction must return null, and the
|
|
267
|
+
// adapter must then fail loud (no parseable JSON) rather than crash.
|
|
268
|
+
const adapter = makeAdapter();
|
|
269
|
+
hoisted.mockReturn = [
|
|
270
|
+
{ role: 'assistant', content: null },
|
|
271
|
+
];
|
|
272
|
+
await expect(adapter.startRun(makeStartRun())).rejects.toThrow(/no parseable JSON|submit_output was not called/);
|
|
273
|
+
});
|
|
274
|
+
it('returns null when the transcript has no assistant message at all', async () => {
|
|
275
|
+
const adapter = makeAdapter();
|
|
276
|
+
hoisted.mockReturn = [
|
|
277
|
+
{ role: 'user', content: 'hello' },
|
|
278
|
+
];
|
|
279
|
+
await expect(adapter.startRun(makeStartRun())).rejects.toThrow(/no parseable JSON|submit_output was not called/);
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
describe('PRI-419 L2AgentLoopAdapter — timeout/abort path (P3-1)', () => {
|
|
283
|
+
it('reports timed_out when the wall-clock budget aborts the loop', async () => {
|
|
284
|
+
// Use a short real totalBudgetMs so the adapter's setTimeout fires and aborts the
|
|
285
|
+
// controller. The mock loop waits past the budget, then rejects (simulating an
|
|
286
|
+
// abort-driven failure). The catch block must classify it as timed_out.
|
|
287
|
+
const adapter = makeAdapter({ totalBudgetMs: 50 });
|
|
288
|
+
hoisted.impl = async (...args) => {
|
|
289
|
+
// Wait long enough for the budget timer to fire + abort. signal is the 5th arg.
|
|
290
|
+
const signal = args[4];
|
|
291
|
+
await new Promise(resolve => setTimeout(resolve, 120));
|
|
292
|
+
if (signal?.aborted) {
|
|
293
|
+
throw new Error('aborted by budget');
|
|
294
|
+
}
|
|
295
|
+
return [];
|
|
296
|
+
};
|
|
297
|
+
await expect(adapter.startRun(makeStartRun())).rejects.toThrow(/aborted by budget/);
|
|
298
|
+
const completeCalls = emitTelemetryMock.mock.calls.filter(c => c[0]?.eventType === 'dreamer_l2_complete');
|
|
299
|
+
expect(completeCalls.length).toBe(1);
|
|
300
|
+
expect(completeCalls[0]?.[0]?.payload?.timedOut).toBe(true);
|
|
301
|
+
}, 10_000);
|
|
302
|
+
it('reports execution_failed (not timed_out) when the loop throws without abort', async () => {
|
|
303
|
+
const adapter = makeAdapter({ totalBudgetMs: 60_000 });
|
|
304
|
+
hoisted.impl = async () => {
|
|
305
|
+
throw new Error('model error');
|
|
306
|
+
};
|
|
307
|
+
await expect(adapter.startRun(makeStartRun())).rejects.toThrow(/model error/);
|
|
308
|
+
const completeCalls = emitTelemetryMock.mock.calls.filter(c => c[0]?.eventType === 'dreamer_l2_complete');
|
|
309
|
+
expect(completeCalls.length).toBe(1);
|
|
310
|
+
expect(completeCalls[0]?.[0]?.payload?.timedOut).toBe(false);
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
describe('PRI-420 L2AgentLoopAdapter — empty-response auto-retry', () => {
|
|
314
|
+
it('retries on empty response and succeeds on the second attempt', async () => {
|
|
315
|
+
const adapter = makeAdapter({ maxEmptyRetries: 2, totalBudgetMs: 60_000 });
|
|
316
|
+
let attempt = 0;
|
|
317
|
+
hoisted.impl = async (_p, context) => {
|
|
318
|
+
attempt += 1;
|
|
319
|
+
if (attempt === 1) {
|
|
320
|
+
// First attempt: empty response (no submit_output, no text).
|
|
321
|
+
return [{ role: 'assistant', content: '' }];
|
|
322
|
+
}
|
|
323
|
+
// Second attempt: call submit_output.
|
|
324
|
+
const submit = context.tools?.find(t => t.name === 'submit_output');
|
|
325
|
+
if (submit)
|
|
326
|
+
await submit.execute('call-1', VALID_DREAMER_OUTPUT);
|
|
327
|
+
return [];
|
|
328
|
+
};
|
|
329
|
+
const handle = await adapter.startRun(makeStartRun());
|
|
330
|
+
const output = await adapter.fetchOutput(handle.runId);
|
|
331
|
+
expect(output).not.toBeNull();
|
|
332
|
+
expect(output?.payload).toEqual(VALID_DREAMER_OUTPUT);
|
|
333
|
+
// retryCount should be 1 in telemetry.
|
|
334
|
+
const completeCalls = emitTelemetryMock.mock.calls.filter(c => c[0]?.eventType === 'dreamer_l2_complete');
|
|
335
|
+
expect(completeCalls[0]?.[0]?.payload?.retryCount).toBe(1);
|
|
336
|
+
});
|
|
337
|
+
it('emits empty_response_retry telemetry per retry', async () => {
|
|
338
|
+
const adapter = makeAdapter({ maxEmptyRetries: 2, totalBudgetMs: 60_000 });
|
|
339
|
+
let attempt = 0;
|
|
340
|
+
hoisted.impl = async (_p, context) => {
|
|
341
|
+
attempt += 1;
|
|
342
|
+
if (attempt <= 2) {
|
|
343
|
+
return [{ role: 'assistant', content: '' }]; // empty
|
|
344
|
+
}
|
|
345
|
+
const submit = context.tools?.find(t => t.name === 'submit_output');
|
|
346
|
+
if (submit)
|
|
347
|
+
await submit.execute('call-1', VALID_DREAMER_OUTPUT);
|
|
348
|
+
return [];
|
|
349
|
+
};
|
|
350
|
+
await adapter.startRun(makeStartRun());
|
|
351
|
+
const retryEvents = emitTelemetryMock.mock.calls.filter(c => c[0]?.eventType === 'dreamer_l2_turn' && c[0]?.payload?.phase === 'empty_response_retry');
|
|
352
|
+
expect(retryEvents.length).toBe(2); // attempt 1 and attempt 2
|
|
353
|
+
});
|
|
354
|
+
it('does NOT retry when maxEmptyRetries is 0 (fails immediately to fallback)', async () => {
|
|
355
|
+
const adapter = makeAdapter({ maxEmptyRetries: 0, l2FallbackToL1: false, totalBudgetMs: 60_000 });
|
|
356
|
+
hoisted.mockReturn = [{ role: 'assistant', content: '' }];
|
|
357
|
+
await expect(adapter.startRun(makeStartRun())).rejects.toThrow(/empty response on all attempts/);
|
|
358
|
+
const completeCalls = emitTelemetryMock.mock.calls.filter(c => c[0]?.eventType === 'dreamer_l2_complete');
|
|
359
|
+
expect(completeCalls[0]?.[0]?.payload?.retryCount).toBe(0);
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
describe('PRI-420 L2AgentLoopAdapter — L2→L1 fallback', () => {
|
|
363
|
+
it('falls back to L1 completeSimple when all L2 attempts produce empty responses', async () => {
|
|
364
|
+
const adapter = makeAdapter({ maxEmptyRetries: 1, l2FallbackToL1: true, totalBudgetMs: 60_000 });
|
|
365
|
+
hoisted.mockReturn = [{ role: 'assistant', content: '' }]; // always empty
|
|
366
|
+
// Mock completeSimple to return a valid JSON response.
|
|
367
|
+
mockComplete.mockResolvedValueOnce({
|
|
368
|
+
content: JSON.stringify(VALID_DREAMER_OUTPUT),
|
|
369
|
+
});
|
|
370
|
+
const handle = await adapter.startRun(makeStartRun());
|
|
371
|
+
const output = await adapter.fetchOutput(handle.runId);
|
|
372
|
+
expect(output?.payload).toEqual(VALID_DREAMER_OUTPUT);
|
|
373
|
+
// Fallback telemetry should fire.
|
|
374
|
+
const fallbackEvents = emitTelemetryMock.mock.calls.filter(c => c[0]?.eventType === 'dreamer_l2_fallback_to_l1');
|
|
375
|
+
expect(fallbackEvents.length).toBe(1);
|
|
376
|
+
expect(fallbackEvents[0]?.[0]?.payload?.reason).toContain('empty response');
|
|
377
|
+
});
|
|
378
|
+
it('fails loud (R9) when both L2 and L1 fallback fail', async () => {
|
|
379
|
+
const adapter = makeAdapter({ maxEmptyRetries: 1, l2FallbackToL1: true, totalBudgetMs: 60_000 });
|
|
380
|
+
hoisted.mockReturn = [{ role: 'assistant', content: '' }]; // L2 empty
|
|
381
|
+
mockComplete.mockResolvedValueOnce({ content: 'not json at all' }); // L1 no parseable JSON
|
|
382
|
+
await expect(adapter.startRun(makeStartRun())).rejects.toThrow(/L1 fallback also failed/);
|
|
383
|
+
});
|
|
384
|
+
it('fails loud without L1 fallback when l2FallbackToL1 is false', async () => {
|
|
385
|
+
const adapter = makeAdapter({ maxEmptyRetries: 1, l2FallbackToL1: false, totalBudgetMs: 60_000 });
|
|
386
|
+
hoisted.mockReturn = [{ role: 'assistant', content: '' }];
|
|
387
|
+
await expect(adapter.startRun(makeStartRun())).rejects.toThrow(/empty response on all attempts/);
|
|
388
|
+
// No fallback event should fire.
|
|
389
|
+
const fallbackEvents = emitTelemetryMock.mock.calls.filter(c => c[0]?.eventType === 'dreamer_l2_fallback_to_l1');
|
|
390
|
+
expect(fallbackEvents.length).toBe(0);
|
|
391
|
+
});
|
|
392
|
+
});
|
|
393
|
+
describe('PRI-419 L2AgentLoopAdapter — runs Map is bounded (P1-1)', () => {
|
|
394
|
+
it('does not grow without bound across many runs', async () => {
|
|
395
|
+
const adapter = makeAdapter();
|
|
396
|
+
// Run more than MAX_RETAINED_RUNS (100) times; the Map must stay bounded.
|
|
397
|
+
for (let i = 0; i < 105; i++) {
|
|
398
|
+
hoisted.impl = async (_p, context) => {
|
|
399
|
+
const submit = context.tools?.find(t => t.name === 'submit_output');
|
|
400
|
+
if (submit)
|
|
401
|
+
await submit.execute('call-1', VALID_DREAMER_OUTPUT);
|
|
402
|
+
return [];
|
|
403
|
+
};
|
|
404
|
+
await adapter.startRun(makeStartRun());
|
|
405
|
+
}
|
|
406
|
+
// The internal runs Map is private; verify via fetchOutput that early runIds are evicted
|
|
407
|
+
// (not retained) while recent ones are. We can't read the Map directly, but pollRun on an
|
|
408
|
+
// early runId must report it as failed (evicted → unknown runId default).
|
|
409
|
+
// Collect the first runId via telemetry and assert it is no longer fetchable.
|
|
410
|
+
const firstComplete = emitTelemetryMock.mock.calls.find(c => c[0]?.eventType === 'dreamer_l2_complete');
|
|
411
|
+
const firstRunId = firstComplete?.[0]?.payload?.runId;
|
|
412
|
+
// The very first runId should have been evicted after 105 runs (>100 cap).
|
|
413
|
+
if (firstRunId) {
|
|
414
|
+
const output = await adapter.fetchOutput(firstRunId);
|
|
415
|
+
// Either null (evicted) or still present if the cap is generous — assert null to prove eviction.
|
|
416
|
+
expect(output).toBeNull();
|
|
417
|
+
}
|
|
418
|
+
}, 30_000);
|
|
419
|
+
});
|
|
420
|
+
//# sourceMappingURL=l2-agent-loop-adapter.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"l2-agent-loop-adapter.test.js","sourceRoot":"","sources":["../../../../src/runtime-v2/adapter/__tests__/l2-agent-loop-adapter.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import type { StoreEventEmitter } from '../store/event-emitter.js';
|
|
2
|
+
import type { PDRuntimeAdapter, RuntimeKind, RuntimeCapabilities, RuntimeHealth, RunHandle, RunStatus, StartRunInput, StructuredRunOutput, RuntimeArtifactRef } from '../runtime-protocol.js';
|
|
3
|
+
import { type PdL2ArtifactReader, type PdL2PrincipleReader } from '../tools/agent-tool-contract.js';
|
|
4
|
+
/** Configuration for L2AgentLoopAdapter. */
|
|
5
|
+
export interface L2AgentLoopAdapterConfig {
|
|
6
|
+
/** Provider id (e.g. 'openai', 'anthropic'). */
|
|
7
|
+
provider: string;
|
|
8
|
+
/** Model id. */
|
|
9
|
+
model: string;
|
|
10
|
+
/** Env var name holding the API key. */
|
|
11
|
+
apiKeyEnv: string;
|
|
12
|
+
/** Optional custom base URL (OpenAI-compatible endpoints). */
|
|
13
|
+
baseUrl?: string;
|
|
14
|
+
/** Optional workspace path (for diagnostics only). */
|
|
15
|
+
workspace?: string;
|
|
16
|
+
/** Optional event emitter; defaults to the shared singleton. */
|
|
17
|
+
eventEmitter?: StoreEventEmitter;
|
|
18
|
+
/** Max agent-loop turns before forced stop (default 5). */
|
|
19
|
+
maxTurns?: number;
|
|
20
|
+
/** Total wall-clock budget for the whole loop in ms (default 300_000). */
|
|
21
|
+
totalBudgetMs?: number;
|
|
22
|
+
/**
|
|
23
|
+
* PRI-420: max auto-retries when the agent loop returns an empty response (no submit_output
|
|
24
|
+
* capture and no parseable text). The model API occasionally returns content=[] on long prompts;
|
|
25
|
+
* retrying with fresh state recovers ~100%. Default 2. Set to 0 to disable.
|
|
26
|
+
*/
|
|
27
|
+
maxEmptyRetries?: number;
|
|
28
|
+
/**
|
|
29
|
+
* PRI-420: when true (default), if all L2 attempts fail, fall back to a one-shot completeSimple
|
|
30
|
+
* call (L1 equivalent) so the dreamer still produces output. Emits dreamer_l2_fallback_to_l1.
|
|
31
|
+
* Set to false to fail loud without fallback.
|
|
32
|
+
*/
|
|
33
|
+
l2FallbackToL1?: boolean;
|
|
34
|
+
}
|
|
35
|
+
/** Read-only readers injected by the factory (bound to the dreamer's task + stores). */
|
|
36
|
+
export interface L2AgentLoopAdapterDeps {
|
|
37
|
+
artifactReader: PdL2ArtifactReader;
|
|
38
|
+
principleReader: PdL2PrincipleReader;
|
|
39
|
+
}
|
|
40
|
+
export declare class L2AgentLoopAdapter implements PDRuntimeAdapter {
|
|
41
|
+
private readonly config;
|
|
42
|
+
private readonly deps;
|
|
43
|
+
private readonly eventEmitter;
|
|
44
|
+
private readonly runs;
|
|
45
|
+
private readonly abortControllers;
|
|
46
|
+
constructor(config: L2AgentLoopAdapterConfig, deps: L2AgentLoopAdapterDeps);
|
|
47
|
+
kind(): RuntimeKind;
|
|
48
|
+
getCapabilities(): Promise<RuntimeCapabilities>;
|
|
49
|
+
refreshCapabilities(): Promise<RuntimeCapabilities>;
|
|
50
|
+
healthCheck(): Promise<RuntimeHealth>;
|
|
51
|
+
startRun(input: StartRunInput): Promise<RunHandle>;
|
|
52
|
+
/**
|
|
53
|
+
* PRI-420: L1 one-shot fallback. Runs a single completeSimple call with the same prompt
|
|
54
|
+
* (without tool instructions) and extracts JSON from the response. This is the safety net
|
|
55
|
+
* when all L2 attempts fail — it ensures the dreamer still produces output.
|
|
56
|
+
*/
|
|
57
|
+
private runL1Fallback;
|
|
58
|
+
pollRun(runId: string): Promise<RunStatus>;
|
|
59
|
+
cancelRun(runId: string): Promise<void>;
|
|
60
|
+
fetchOutput(runId: string): Promise<StructuredRunOutput | null>;
|
|
61
|
+
fetchArtifacts(_runId: string): Promise<RuntimeArtifactRef[]>;
|
|
62
|
+
/**
|
|
63
|
+
* Bound the runs Map to MAX_RETAINED_RUNS to prevent unbounded memory growth in
|
|
64
|
+
* long-running services (the auto-consumer wakes every 120s). Evicts the oldest
|
|
65
|
+
* entries by insertion order (Map preserves it). Called at the start of each run.
|
|
66
|
+
*/
|
|
67
|
+
private evictOldRuns;
|
|
68
|
+
private emitComplete;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=l2-agent-loop-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"l2-agent-loop-adapter.d.ts","sourceRoot":"","sources":["../../../src/runtime-v2/adapter/l2-agent-loop-adapter.ts"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAKnE,OAAO,KAAK,EACV,gBAAgB,EAChB,WAAW,EACX,mBAAmB,EACnB,aAAa,EACb,SAAS,EACT,SAAS,EACT,aAAa,EACb,mBAAmB,EACnB,kBAAkB,EACnB,MAAM,wBAAwB,CAAC;AAChC,OAAO,EAIL,KAAK,kBAAkB,EACvB,KAAK,mBAAmB,EAEzB,MAAM,iCAAiC,CAAC;AAEzC,4CAA4C;AAC5C,MAAM,WAAW,wBAAwB;IACvC,gDAAgD;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,wCAAwC;IACxC,SAAS,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gEAAgE;IAChE,YAAY,CAAC,EAAE,iBAAiB,CAAC;IACjC,2DAA2D;IAC3D,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;OAIG;IACH,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAsDD,wFAAwF;AACxF,MAAM,WAAW,sBAAsB;IACrC,cAAc,EAAE,kBAAkB,CAAC;IACnC,eAAe,EAAE,mBAAmB,CAAC;CACtC;AAuDD,qBAAa,kBAAmB,YAAW,gBAAgB;IACzD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2B;IAClD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAyB;IAC9C,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAoB;IACjD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAiC;IACtD,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAAsC;gBAE3D,MAAM,EAAE,wBAAwB,EAAE,IAAI,EAAE,sBAAsB;IAO1E,IAAI,IAAI,WAAW;IAKb,eAAe,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAc/C,mBAAmB,IAAI,OAAO,CAAC,mBAAmB,CAAC;IAInD,WAAW,IAAI,OAAO,CAAC,aAAa,CAAC;IAmBrC,QAAQ,CAAC,KAAK,EAAE,aAAa,GAAG,OAAO,CAAC,SAAS,CAAC;IAgQxD;;;;OAIG;YACW,aAAa;IA0BrB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,CAAC;IAe1C,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOvC,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,mBAAmB,GAAG,IAAI,CAAC;IAM/D,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,EAAE,CAAC;IAKnE;;;;OAIG;IACH,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,YAAY;CA0BrB"}
|