@united-workforce/cli 0.7.0 → 0.8.1
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 +32 -5
- package/dist/.build-fingerprint +1 -0
- package/dist/__tests__/broker-step-active-turns.test.d.ts +20 -0
- package/dist/__tests__/broker-step-active-turns.test.d.ts.map +1 -0
- package/dist/__tests__/broker-step-active-turns.test.js +428 -0
- package/dist/__tests__/broker-step-active-turns.test.js.map +1 -0
- package/dist/__tests__/broker-step-turn-chain-phase2.test.d.ts +13 -0
- package/dist/__tests__/broker-step-turn-chain-phase2.test.d.ts.map +1 -0
- package/dist/__tests__/broker-step-turn-chain-phase2.test.js +429 -0
- package/dist/__tests__/broker-step-turn-chain-phase2.test.js.map +1 -0
- package/dist/__tests__/e2e-broker-step-suspend.test.d.ts +18 -0
- package/dist/__tests__/e2e-broker-step-suspend.test.d.ts.map +1 -0
- package/dist/__tests__/e2e-broker-step-suspend.test.js +313 -0
- package/dist/__tests__/e2e-broker-step-suspend.test.js.map +1 -0
- package/dist/__tests__/e2e-thread-resume-timeout-suspend.test.d.ts +28 -0
- package/dist/__tests__/e2e-thread-resume-timeout-suspend.test.d.ts.map +1 -0
- package/dist/__tests__/e2e-thread-resume-timeout-suspend.test.js +322 -0
- package/dist/__tests__/e2e-thread-resume-timeout-suspend.test.js.map +1 -0
- package/dist/__tests__/log-tag-validity.test.d.ts +2 -0
- package/dist/__tests__/log-tag-validity.test.d.ts.map +1 -0
- package/dist/__tests__/log-tag-validity.test.js +110 -0
- package/dist/__tests__/log-tag-validity.test.js.map +1 -0
- package/dist/__tests__/setup-agent-discovery.test.js +23 -23
- package/dist/__tests__/setup-agent-discovery.test.js.map +1 -1
- package/dist/__tests__/step-show-json.test.js +5 -5
- package/dist/__tests__/step-show-json.test.js.map +1 -1
- package/dist/__tests__/step-show-text.test.d.ts +2 -0
- package/dist/__tests__/step-show-text.test.d.ts.map +1 -0
- package/dist/__tests__/step-show-text.test.js +192 -0
- package/dist/__tests__/step-show-text.test.js.map +1 -0
- package/dist/__tests__/step-turns-cli-subprocess.test.d.ts +21 -0
- package/dist/__tests__/step-turns-cli-subprocess.test.d.ts.map +1 -0
- package/dist/__tests__/step-turns-cli-subprocess.test.js +356 -0
- package/dist/__tests__/step-turns-cli-subprocess.test.js.map +1 -0
- package/dist/__tests__/step-turns-panorama-phase3.test.d.ts +21 -0
- package/dist/__tests__/step-turns-panorama-phase3.test.d.ts.map +1 -0
- package/dist/__tests__/step-turns-panorama-phase3.test.js +476 -0
- package/dist/__tests__/step-turns-panorama-phase3.test.js.map +1 -0
- package/dist/__tests__/step-turns.test.d.ts +24 -0
- package/dist/__tests__/step-turns.test.d.ts.map +1 -0
- package/dist/__tests__/step-turns.test.js +646 -0
- package/dist/__tests__/step-turns.test.js.map +1 -0
- package/dist/__tests__/store-turn-chain.test.d.ts +2 -0
- package/dist/__tests__/store-turn-chain.test.d.ts.map +1 -0
- package/dist/__tests__/store-turn-chain.test.js +341 -0
- package/dist/__tests__/store-turn-chain.test.js.map +1 -0
- package/dist/__tests__/thread-list-limit-offset.test.d.ts +24 -0
- package/dist/__tests__/thread-list-limit-offset.test.d.ts.map +1 -0
- package/dist/__tests__/thread-list-limit-offset.test.js +254 -0
- package/dist/__tests__/thread-list-limit-offset.test.js.map +1 -0
- package/dist/__tests__/thread-list-template-ms-date.test.js +7 -2
- package/dist/__tests__/thread-list-template-ms-date.test.js.map +1 -1
- package/dist/__tests__/thread.test.js +28 -14
- package/dist/__tests__/thread.test.js.map +1 -1
- package/dist/cli.js +910 -344
- package/dist/cli.js.map +1 -1
- package/dist/commands/broker-step.d.ts +10 -3
- package/dist/commands/broker-step.d.ts.map +1 -1
- package/dist/commands/broker-step.js +231 -27
- package/dist/commands/broker-step.js.map +1 -1
- package/dist/commands/prompt.d.ts.map +1 -1
- package/dist/commands/prompt.js +42 -50
- package/dist/commands/prompt.js.map +1 -1
- package/dist/commands/setup.d.ts +6 -4
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +16 -26
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/step.d.ts +48 -1
- package/dist/commands/step.d.ts.map +1 -1
- package/dist/commands/step.js +496 -3
- package/dist/commands/step.js.map +1 -1
- package/dist/output-mappers.d.ts +8 -0
- package/dist/output-mappers.d.ts.map +1 -1
- package/dist/output-mappers.js +72 -18
- package/dist/output-mappers.js.map +1 -1
- package/dist/schemas.d.ts +3 -0
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +17 -3
- package/dist/schemas.js.map +1 -1
- package/dist/store.d.ts +147 -1
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +254 -1
- package/dist/store.js.map +1 -1
- package/dist/text-renderers.d.ts.map +1 -1
- package/dist/text-renderers.js +27 -2
- package/dist/text-renderers.js.map +1 -1
- package/package.json +7 -6
- package/src/__tests__/broker-step-active-turns.test.ts +509 -0
- package/src/__tests__/broker-step-turn-chain-phase2.test.ts +525 -0
- package/src/__tests__/e2e-broker-step-suspend.test.ts +351 -0
- package/src/__tests__/e2e-thread-resume-timeout-suspend.test.ts +360 -0
- package/src/__tests__/log-tag-validity.test.ts +124 -0
- package/src/__tests__/setup-agent-discovery.test.ts +23 -23
- package/src/__tests__/step-show-json.test.ts +5 -5
- package/src/__tests__/step-show-text.test.ts +236 -0
- package/src/__tests__/step-turns-cli-subprocess.test.ts +411 -0
- package/src/__tests__/step-turns-panorama-phase3.test.ts +579 -0
- package/src/__tests__/step-turns.test.ts +734 -0
- package/src/__tests__/store-turn-chain.test.ts +386 -0
- package/src/__tests__/thread-list-limit-offset.test.ts +305 -0
- package/src/__tests__/thread-list-template-ms-date.test.ts +7 -2
- package/src/__tests__/thread.test.ts +29 -15
- package/src/cli.ts +1056 -483
- package/src/commands/broker-step.ts +315 -38
- package/src/commands/prompt.ts +42 -50
- package/src/commands/setup.ts +16 -28
- package/src/commands/step.ts +655 -3
- package/src/output-mappers.ts +99 -21
- package/src/schemas.ts +32 -2
- package/src/store.ts +297 -2
- package/src/text-renderers.ts +35 -2
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 2 (#419) — Turn chain with prev+owner fields and thread-keyed active vars.
|
|
3
|
+
*
|
|
4
|
+
* Covers the spec acceptance scenarios:
|
|
5
|
+
* 1. onTurn writes each turn with prev pointer and owner reference
|
|
6
|
+
* 2. Step-start/step-complete dual node lifecycle
|
|
7
|
+
* 3. Same role multi-round ownership (#412 regression test)
|
|
8
|
+
* 4. Thread-keyed active vars (not role-keyed)
|
|
9
|
+
* 5. Crash recovery isolation (new attempt gets new step-start)
|
|
10
|
+
* 6. Detail node has no turns array (turns self-contained via chain)
|
|
11
|
+
*/
|
|
12
|
+
import { mkdtemp, rm } from "node:fs/promises";
|
|
13
|
+
import { tmpdir } from "node:os";
|
|
14
|
+
import { join } from "node:path";
|
|
15
|
+
import { putSchema } from "@ocas/core";
|
|
16
|
+
import { createProcessLogger } from "@united-workforce/util";
|
|
17
|
+
import { afterEach, beforeEach, describe, expect, test, vi } from "vitest";
|
|
18
|
+
import { executeBrokerStep } from "../commands/broker-step.js";
|
|
19
|
+
import { ACTIVE_TURNS_VAR_PREFIX, activeStepVarName, activeTurnHeadVarName, createUwfStore, getActiveStep, getActiveTurnHead, turnsOfStep, walkTurnChain, writeStepStart, writeTurnNode, } from "../store.js";
|
|
20
|
+
// ── SSE plumbing ─────────────────────────────────────────────────────────────
|
|
21
|
+
function sseFrame(id, event, data) {
|
|
22
|
+
return `id: ${id}\nevent: ${event}\ndata: ${JSON.stringify(data)}\n\n`;
|
|
23
|
+
}
|
|
24
|
+
function turnFrame(id, index, content) {
|
|
25
|
+
return sseFrame(id, "turn", {
|
|
26
|
+
type: "@sumeru/turn",
|
|
27
|
+
value: { index, role: "assistant", content, timestamp: "", toolCalls: null },
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
function doneFrame(id, turnCount) {
|
|
31
|
+
return sseFrame(id, "done", {
|
|
32
|
+
type: "@sumeru/summary",
|
|
33
|
+
value: { turnCount, tokens: { in: 9, out: 4 }, durationMs: 42 },
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
function delay(ms) {
|
|
37
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
38
|
+
}
|
|
39
|
+
const PER_TURN_MS = 40;
|
|
40
|
+
function buildPacedSseResponse(frames) {
|
|
41
|
+
const encoder = new TextEncoder();
|
|
42
|
+
let cancelled = false;
|
|
43
|
+
const stream = new ReadableStream({
|
|
44
|
+
start(controller) {
|
|
45
|
+
void (async () => {
|
|
46
|
+
try {
|
|
47
|
+
for (const frame of frames) {
|
|
48
|
+
if (cancelled)
|
|
49
|
+
return;
|
|
50
|
+
controller.enqueue(encoder.encode(frame));
|
|
51
|
+
await delay(PER_TURN_MS);
|
|
52
|
+
}
|
|
53
|
+
if (!cancelled)
|
|
54
|
+
controller.close();
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
// Consumer closed/cancelled the stream first
|
|
58
|
+
}
|
|
59
|
+
})();
|
|
60
|
+
},
|
|
61
|
+
cancel() {
|
|
62
|
+
cancelled = true;
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
return new Response(stream, {
|
|
66
|
+
status: 200,
|
|
67
|
+
headers: { "Content-Type": "text/event-stream; charset=utf-8" },
|
|
68
|
+
});
|
|
69
|
+
}
|
|
70
|
+
function buildJsonResponse(status, body) {
|
|
71
|
+
return new Response(JSON.stringify(body), {
|
|
72
|
+
status,
|
|
73
|
+
headers: { "Content-Type": "application/json" },
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
// ── Fixture ──────────────────────────────────────────────────────────────────
|
|
77
|
+
const ROLE_OUTPUT_SCHEMA = {
|
|
78
|
+
title: "coder-output",
|
|
79
|
+
type: "object",
|
|
80
|
+
required: ["$status"],
|
|
81
|
+
properties: {
|
|
82
|
+
$status: { type: "string", enum: ["done", "failed"] },
|
|
83
|
+
summary: { type: "string" },
|
|
84
|
+
},
|
|
85
|
+
additionalProperties: false,
|
|
86
|
+
};
|
|
87
|
+
const FINAL_TURN = `---
|
|
88
|
+
$status: done
|
|
89
|
+
summary: shipped
|
|
90
|
+
---
|
|
91
|
+
the final answer`;
|
|
92
|
+
const HOST = "http://127.0.0.1:7900";
|
|
93
|
+
const GATEWAY = "coder-gw";
|
|
94
|
+
const ALIAS = "coder-agent";
|
|
95
|
+
const SESSION_ID = "ses_turn_chain_phase2";
|
|
96
|
+
const THREAD_ID = "06FDTURNCHAINPHASE2TEST01";
|
|
97
|
+
const ROLE = "coder";
|
|
98
|
+
function buildConfig() {
|
|
99
|
+
return {
|
|
100
|
+
agents: { [ALIAS]: { host: HOST, gateway: GATEWAY } },
|
|
101
|
+
defaultAgent: ALIAS,
|
|
102
|
+
agentOverrides: null,
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
async function buildWorkflow(uwf) {
|
|
106
|
+
const frontmatterHash = (await putSchema(uwf.store, ROLE_OUTPUT_SCHEMA));
|
|
107
|
+
const workflow = {
|
|
108
|
+
version: 1,
|
|
109
|
+
name: "turn-chain-wf",
|
|
110
|
+
description: "phase2 turn chain",
|
|
111
|
+
roles: {
|
|
112
|
+
[ROLE]: {
|
|
113
|
+
description: "writes code",
|
|
114
|
+
goal: "produce a change",
|
|
115
|
+
capabilities: [],
|
|
116
|
+
procedure: "do the work",
|
|
117
|
+
output: "frontmatter+body",
|
|
118
|
+
frontmatter: frontmatterHash,
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
graph: {
|
|
122
|
+
[ROLE]: {
|
|
123
|
+
done: { role: "$END", prompt: "", location: null },
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
};
|
|
127
|
+
const startHash = (await uwf.store.cas.put(uwf.schemas.startNode, {
|
|
128
|
+
workflow: await uwf.store.cas.put(uwf.schemas.workflow, workflow),
|
|
129
|
+
prompt: "task",
|
|
130
|
+
cwd: "/tmp/work",
|
|
131
|
+
}));
|
|
132
|
+
return { workflow, startHash };
|
|
133
|
+
}
|
|
134
|
+
function resolveFetchUrl(input) {
|
|
135
|
+
if (typeof input === "string")
|
|
136
|
+
return input;
|
|
137
|
+
if (input instanceof URL)
|
|
138
|
+
return input.href;
|
|
139
|
+
return input.url;
|
|
140
|
+
}
|
|
141
|
+
function runStep(uwf, workflow, startHash, tmpDir, prevHash = null) {
|
|
142
|
+
return executeBrokerStep({
|
|
143
|
+
storageRoot: tmpDir,
|
|
144
|
+
uwf,
|
|
145
|
+
config: buildConfig(),
|
|
146
|
+
workflow,
|
|
147
|
+
threadId: THREAD_ID,
|
|
148
|
+
role: ROLE,
|
|
149
|
+
edgePrompt: "go",
|
|
150
|
+
effectiveCwd: "/tmp/work",
|
|
151
|
+
startHash,
|
|
152
|
+
prevHash,
|
|
153
|
+
agentOverride: null,
|
|
154
|
+
previousAttempts: null,
|
|
155
|
+
plog: createProcessLogger({
|
|
156
|
+
storageRoot: tmpDir,
|
|
157
|
+
context: { thread: THREAD_ID, workflow: "turn-chain-wf" },
|
|
158
|
+
}),
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
// ── Tests ────────────────────────────────────────────────────────────────────
|
|
162
|
+
describe("turn chain Phase 2 (#419)", () => {
|
|
163
|
+
let tmpDir;
|
|
164
|
+
let casDir;
|
|
165
|
+
let savedOcasHome;
|
|
166
|
+
beforeEach(async () => {
|
|
167
|
+
savedOcasHome = process.env.OCAS_HOME;
|
|
168
|
+
tmpDir = await mkdtemp(join(tmpdir(), "turn-chain-phase2-"));
|
|
169
|
+
casDir = join(tmpDir, "cas");
|
|
170
|
+
process.env.OCAS_HOME = casDir;
|
|
171
|
+
vi.stubGlobal("fetch", async (input, _init) => {
|
|
172
|
+
const url = resolveFetchUrl(input);
|
|
173
|
+
if (url.endsWith(`/gateways/${GATEWAY}/sessions`)) {
|
|
174
|
+
return buildJsonResponse(201, {
|
|
175
|
+
type: "@sumeru/session",
|
|
176
|
+
value: { id: SESSION_ID, gateway: GATEWAY },
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
if (url.endsWith(`/sessions/${SESSION_ID}/messages`)) {
|
|
180
|
+
return buildPacedSseResponse([
|
|
181
|
+
turnFrame(1, 0, "First analysis"),
|
|
182
|
+
turnFrame(2, 1, "Continued work"),
|
|
183
|
+
turnFrame(3, 2, FINAL_TURN),
|
|
184
|
+
doneFrame(4, 3),
|
|
185
|
+
]);
|
|
186
|
+
}
|
|
187
|
+
return buildJsonResponse(500, { error: "unexpected url", url });
|
|
188
|
+
});
|
|
189
|
+
});
|
|
190
|
+
afterEach(async () => {
|
|
191
|
+
vi.unstubAllGlobals();
|
|
192
|
+
if (savedOcasHome === undefined)
|
|
193
|
+
delete process.env.OCAS_HOME;
|
|
194
|
+
else
|
|
195
|
+
process.env.OCAS_HOME = savedOcasHome;
|
|
196
|
+
await rm(tmpDir, { recursive: true, force: true });
|
|
197
|
+
});
|
|
198
|
+
test("onTurn writes each turn with prev pointer and owner reference", async () => {
|
|
199
|
+
const uwf = await createUwfStore(tmpDir);
|
|
200
|
+
const { workflow, startHash } = await buildWorkflow(uwf);
|
|
201
|
+
const result = await runStep(uwf, workflow, startHash, tmpDir);
|
|
202
|
+
expect(result.isError).toBe(false);
|
|
203
|
+
// Get the turn chain head
|
|
204
|
+
const turnHead = getActiveTurnHead(uwf.store, THREAD_ID);
|
|
205
|
+
expect(turnHead).not.toBeNull();
|
|
206
|
+
// Walk the turn chain
|
|
207
|
+
const turnChain = walkTurnChain(uwf, turnHead);
|
|
208
|
+
expect(turnChain).toHaveLength(3);
|
|
209
|
+
// Verify each turn has correct prev and owner
|
|
210
|
+
const turn0 = uwf.store.cas.get(turnChain[0])?.payload;
|
|
211
|
+
const turn1 = uwf.store.cas.get(turnChain[1])?.payload;
|
|
212
|
+
const turn2 = uwf.store.cas.get(turnChain[2])?.payload;
|
|
213
|
+
// Turn 0: first turn, prev is null
|
|
214
|
+
expect(turn0.prev).toBeNull();
|
|
215
|
+
expect(turn0.owner).not.toBeNull();
|
|
216
|
+
expect(turn0.content).toBe("First analysis");
|
|
217
|
+
// Turn 1: prev points to turn 0
|
|
218
|
+
expect(turn1.prev).toBe(turnChain[0]);
|
|
219
|
+
expect(turn1.owner).toBe(turn0.owner);
|
|
220
|
+
expect(turn1.content).toBe("Continued work");
|
|
221
|
+
// Turn 2: prev points to turn 1
|
|
222
|
+
expect(turn2.prev).toBe(turnChain[1]);
|
|
223
|
+
expect(turn2.owner).toBe(turn0.owner);
|
|
224
|
+
expect(turn2.content).toBe(FINAL_TURN);
|
|
225
|
+
// All turns have same owner (the step-start)
|
|
226
|
+
expect(turn0.owner).toBe(turn1.owner);
|
|
227
|
+
expect(turn1.owner).toBe(turn2.owner);
|
|
228
|
+
});
|
|
229
|
+
test("step-start is written at entry and active-step var is set", async () => {
|
|
230
|
+
const uwf = await createUwfStore(tmpDir);
|
|
231
|
+
const { workflow, startHash } = await buildWorkflow(uwf);
|
|
232
|
+
// Capture active-step during execution
|
|
233
|
+
let activeStepDuringExec = null;
|
|
234
|
+
const originalFetch = globalThis.fetch;
|
|
235
|
+
vi.stubGlobal("fetch", async (input, init) => {
|
|
236
|
+
const url = resolveFetchUrl(input);
|
|
237
|
+
if (url.endsWith(`/sessions/${SESSION_ID}/messages`)) {
|
|
238
|
+
// Sample active-step while broker is in flight
|
|
239
|
+
activeStepDuringExec = getActiveStep(uwf.store, THREAD_ID);
|
|
240
|
+
}
|
|
241
|
+
return originalFetch(input, init);
|
|
242
|
+
});
|
|
243
|
+
const result = await runStep(uwf, workflow, startHash, tmpDir);
|
|
244
|
+
expect(result.isError).toBe(false);
|
|
245
|
+
// active-step was set during execution
|
|
246
|
+
expect(activeStepDuringExec).not.toBeNull();
|
|
247
|
+
// active-step is cleared after completion
|
|
248
|
+
const activeStepAfter = getActiveStep(uwf.store, THREAD_ID);
|
|
249
|
+
expect(activeStepAfter).toBeNull();
|
|
250
|
+
// Verify step-start node exists and has correct structure
|
|
251
|
+
const stepStartNode = uwf.store.cas.get(activeStepDuringExec);
|
|
252
|
+
expect(stepStartNode).not.toBeNull();
|
|
253
|
+
const stepStartPayload = stepStartNode?.payload;
|
|
254
|
+
expect(stepStartPayload.role).toBe(ROLE);
|
|
255
|
+
expect(stepStartPayload.edgePrompt).toBe("go");
|
|
256
|
+
expect(stepStartPayload.stepIndex).toBe(0);
|
|
257
|
+
expect(stepStartPayload.prev).toBeNull();
|
|
258
|
+
expect(stepStartPayload.start).toBe(startHash);
|
|
259
|
+
});
|
|
260
|
+
test("detail node has no turns array (turns self-contained via chain)", async () => {
|
|
261
|
+
const uwf = await createUwfStore(tmpDir);
|
|
262
|
+
const { workflow, startHash } = await buildWorkflow(uwf);
|
|
263
|
+
const result = await runStep(uwf, workflow, startHash, tmpDir);
|
|
264
|
+
expect(result.isError).toBe(false);
|
|
265
|
+
// Get detail node
|
|
266
|
+
const detailNode = uwf.store.cas.get(result.detailHash);
|
|
267
|
+
expect(detailNode).not.toBeNull();
|
|
268
|
+
const detail = detailNode?.payload;
|
|
269
|
+
// Detail should have sessionId, duration, turnCount but NOT turns array
|
|
270
|
+
expect(detail.sessionId).toBe(SESSION_ID);
|
|
271
|
+
expect(typeof detail.duration).toBe("number");
|
|
272
|
+
expect(detail.turnCount).toBe(3);
|
|
273
|
+
expect(detail.turns).toBeUndefined(); // No turns array in Phase 2
|
|
274
|
+
});
|
|
275
|
+
test("thread-keyed active vars exist, role-keyed do not", async () => {
|
|
276
|
+
const uwf = await createUwfStore(tmpDir);
|
|
277
|
+
const { workflow, startHash } = await buildWorkflow(uwf);
|
|
278
|
+
await runStep(uwf, workflow, startHash, tmpDir);
|
|
279
|
+
// Thread-keyed turn head exists
|
|
280
|
+
const turnHeadVars = uwf.varStore.list({
|
|
281
|
+
exactName: activeTurnHeadVarName(THREAD_ID),
|
|
282
|
+
});
|
|
283
|
+
expect(turnHeadVars.length).toBe(1);
|
|
284
|
+
// Active-step var is cleared (step completed)
|
|
285
|
+
const activeStepVars = uwf.varStore.list({
|
|
286
|
+
exactName: activeStepVarName(THREAD_ID),
|
|
287
|
+
});
|
|
288
|
+
expect(activeStepVars.length).toBe(0);
|
|
289
|
+
// Role-keyed var is also cleared (backward compat cleanup)
|
|
290
|
+
const roleKeyedVars = uwf.varStore.list({
|
|
291
|
+
namePrefix: `${ACTIVE_TURNS_VAR_PREFIX}${THREAD_ID}/`,
|
|
292
|
+
});
|
|
293
|
+
expect(roleKeyedVars.length).toBe(0);
|
|
294
|
+
});
|
|
295
|
+
test("turnsOfStep filters turns by owner", async () => {
|
|
296
|
+
const uwf = await createUwfStore(tmpDir);
|
|
297
|
+
const { workflow, startHash } = await buildWorkflow(uwf);
|
|
298
|
+
const result = await runStep(uwf, workflow, startHash, tmpDir);
|
|
299
|
+
expect(result.isError).toBe(false);
|
|
300
|
+
const turnHead = getActiveTurnHead(uwf.store, THREAD_ID);
|
|
301
|
+
expect(turnHead).not.toBeNull();
|
|
302
|
+
// Get the step-start from the first turn's owner
|
|
303
|
+
const firstTurn = uwf.store.cas.get(walkTurnChain(uwf, turnHead)[0])
|
|
304
|
+
?.payload;
|
|
305
|
+
const stepStartHash = firstTurn.owner;
|
|
306
|
+
// turnsOfStep should return all 3 turns for this step
|
|
307
|
+
const stepTurns = turnsOfStep(uwf, turnHead, stepStartHash);
|
|
308
|
+
expect(stepTurns).toHaveLength(3);
|
|
309
|
+
// A different step-start should return no turns
|
|
310
|
+
const otherStepStart = writeStepStart(uwf, {
|
|
311
|
+
role: "other",
|
|
312
|
+
edgePrompt: "other",
|
|
313
|
+
stepIndex: 1,
|
|
314
|
+
prev: stepStartHash,
|
|
315
|
+
start: startHash,
|
|
316
|
+
startedAtMs: Date.now(),
|
|
317
|
+
cwd: "/tmp",
|
|
318
|
+
});
|
|
319
|
+
const otherTurns = turnsOfStep(uwf, turnHead, otherStepStart);
|
|
320
|
+
expect(otherTurns).toHaveLength(0);
|
|
321
|
+
});
|
|
322
|
+
});
|
|
323
|
+
describe("turn chain unit tests", () => {
|
|
324
|
+
let tmpDir;
|
|
325
|
+
let savedOcasHome;
|
|
326
|
+
beforeEach(async () => {
|
|
327
|
+
savedOcasHome = process.env.OCAS_HOME;
|
|
328
|
+
tmpDir = await mkdtemp(join(tmpdir(), "turn-chain-unit-"));
|
|
329
|
+
process.env.OCAS_HOME = join(tmpDir, "cas");
|
|
330
|
+
});
|
|
331
|
+
afterEach(async () => {
|
|
332
|
+
if (savedOcasHome === undefined)
|
|
333
|
+
delete process.env.OCAS_HOME;
|
|
334
|
+
else
|
|
335
|
+
process.env.OCAS_HOME = savedOcasHome;
|
|
336
|
+
await rm(tmpDir, { recursive: true, force: true });
|
|
337
|
+
});
|
|
338
|
+
test("same role multi-round: turns have correct owner (#412 regression)", async () => {
|
|
339
|
+
const uwf = await createUwfStore(tmpDir);
|
|
340
|
+
const startRef = (await uwf.store.cas.put(uwf.schemas.text, "thread-start"));
|
|
341
|
+
// Round 1: developer
|
|
342
|
+
const ss_dev1 = writeStepStart(uwf, {
|
|
343
|
+
role: "developer",
|
|
344
|
+
edgePrompt: "Implement",
|
|
345
|
+
stepIndex: 0,
|
|
346
|
+
prev: null,
|
|
347
|
+
start: startRef,
|
|
348
|
+
startedAtMs: 1000,
|
|
349
|
+
cwd: "/repo",
|
|
350
|
+
});
|
|
351
|
+
const t1 = writeTurnNode(uwf, { role: "assistant", content: "T1", prev: null, owner: ss_dev1 });
|
|
352
|
+
const t2 = writeTurnNode(uwf, { role: "assistant", content: "T2", prev: t1, owner: ss_dev1 });
|
|
353
|
+
// Reviewer
|
|
354
|
+
const ss_rev = writeStepStart(uwf, {
|
|
355
|
+
role: "reviewer",
|
|
356
|
+
edgePrompt: "Review",
|
|
357
|
+
stepIndex: 1,
|
|
358
|
+
prev: ss_dev1,
|
|
359
|
+
start: startRef,
|
|
360
|
+
startedAtMs: 2000,
|
|
361
|
+
cwd: "/repo",
|
|
362
|
+
});
|
|
363
|
+
const t3 = writeTurnNode(uwf, { role: "assistant", content: "T3", prev: t2, owner: ss_rev });
|
|
364
|
+
const t4 = writeTurnNode(uwf, { role: "assistant", content: "T4", prev: t3, owner: ss_rev });
|
|
365
|
+
// Round 2: developer again (same role, different step-start)
|
|
366
|
+
const ss_dev2 = writeStepStart(uwf, {
|
|
367
|
+
role: "developer",
|
|
368
|
+
edgePrompt: "Fix issues",
|
|
369
|
+
stepIndex: 2,
|
|
370
|
+
prev: ss_rev,
|
|
371
|
+
start: startRef,
|
|
372
|
+
startedAtMs: 3000,
|
|
373
|
+
cwd: "/repo",
|
|
374
|
+
});
|
|
375
|
+
const t5 = writeTurnNode(uwf, { role: "assistant", content: "T5", prev: t4, owner: ss_dev2 });
|
|
376
|
+
// Verify ownership
|
|
377
|
+
expect((uwf.store.cas.get(t1)?.payload).owner).toBe(ss_dev1);
|
|
378
|
+
expect((uwf.store.cas.get(t2)?.payload).owner).toBe(ss_dev1);
|
|
379
|
+
expect((uwf.store.cas.get(t3)?.payload).owner).toBe(ss_rev);
|
|
380
|
+
expect((uwf.store.cas.get(t4)?.payload).owner).toBe(ss_rev);
|
|
381
|
+
expect((uwf.store.cas.get(t5)?.payload).owner).toBe(ss_dev2);
|
|
382
|
+
// turnsOfStep correctly filters by owner
|
|
383
|
+
expect(turnsOfStep(uwf, t5, ss_dev1)).toEqual([t1, t2]);
|
|
384
|
+
expect(turnsOfStep(uwf, t5, ss_rev)).toEqual([t3, t4]);
|
|
385
|
+
expect(turnsOfStep(uwf, t5, ss_dev2)).toEqual([t5]);
|
|
386
|
+
// Step-start chain is correct
|
|
387
|
+
expect((uwf.store.cas.get(ss_dev2)?.payload).prev).toBe(ss_rev);
|
|
388
|
+
expect((uwf.store.cas.get(ss_rev)?.payload).prev).toBe(ss_dev1);
|
|
389
|
+
expect((uwf.store.cas.get(ss_dev1)?.payload).prev).toBeNull();
|
|
390
|
+
});
|
|
391
|
+
test("crash recovery: new attempt gets new step-start, old turns orphaned", async () => {
|
|
392
|
+
const uwf = await createUwfStore(tmpDir);
|
|
393
|
+
const startRef = (await uwf.store.cas.put(uwf.schemas.text, "thread-start"));
|
|
394
|
+
// Attempt 1 (crashed): step-start SS1 with 2 turns
|
|
395
|
+
const ss1 = writeStepStart(uwf, {
|
|
396
|
+
role: "developer",
|
|
397
|
+
edgePrompt: "Implement",
|
|
398
|
+
stepIndex: 0,
|
|
399
|
+
prev: null,
|
|
400
|
+
start: startRef,
|
|
401
|
+
startedAtMs: 1000,
|
|
402
|
+
cwd: "/repo",
|
|
403
|
+
});
|
|
404
|
+
const t1 = writeTurnNode(uwf, { role: "assistant", content: "Old T1", prev: null, owner: ss1 });
|
|
405
|
+
const t2 = writeTurnNode(uwf, { role: "assistant", content: "Old T2", prev: t1, owner: ss1 });
|
|
406
|
+
// Attempt 2 (recovery): new step-start SS2
|
|
407
|
+
const ss2 = writeStepStart(uwf, {
|
|
408
|
+
role: "developer",
|
|
409
|
+
edgePrompt: "Implement",
|
|
410
|
+
stepIndex: 0,
|
|
411
|
+
prev: null, // Same prev as SS1 (recovery starts fresh)
|
|
412
|
+
start: startRef,
|
|
413
|
+
startedAtMs: 2000,
|
|
414
|
+
cwd: "/repo",
|
|
415
|
+
});
|
|
416
|
+
// New turns link to global chain (prev=t2) but have different owner
|
|
417
|
+
const t3 = writeTurnNode(uwf, { role: "assistant", content: "New T3", prev: t2, owner: ss2 });
|
|
418
|
+
const t4 = writeTurnNode(uwf, { role: "assistant", content: "New T4", prev: t3, owner: ss2 });
|
|
419
|
+
// SS1 and SS2 have different hashes
|
|
420
|
+
expect(ss1).not.toBe(ss2);
|
|
421
|
+
// Old attempt's turns belong to SS1
|
|
422
|
+
expect(turnsOfStep(uwf, t4, ss1)).toEqual([t1, t2]);
|
|
423
|
+
// New attempt's turns belong to SS2
|
|
424
|
+
expect(turnsOfStep(uwf, t4, ss2)).toEqual([t3, t4]);
|
|
425
|
+
// Walking the full chain shows all 4 turns
|
|
426
|
+
expect(walkTurnChain(uwf, t4)).toEqual([t1, t2, t3, t4]);
|
|
427
|
+
});
|
|
428
|
+
});
|
|
429
|
+
//# sourceMappingURL=broker-step-turn-chain-phase2.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"broker-step-turn-chain-phase2.test.js","sourceRoot":"","sources":["../../src/__tests__/broker-step-turn-chain-phase2.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Spec 3 (issue #435, Phase 2) — `executeBrokerStep` routes a broker
|
|
3
|
+
* `kind:"suspended"` SendResult through the existing `$SUSPEND` exit.
|
|
4
|
+
*
|
|
5
|
+
* Stubs `globalThis.fetch` so the Sumeru `sendMessage` SSE stream ends in a
|
|
6
|
+
* `suspend` terminal event (send timeout) rather than `done`. Verifies:
|
|
7
|
+
* 1. `executeBrokerStep` takes the suspended branch (NOT the frontmatter
|
|
8
|
+
* retry / error path) and returns `isError === false` with
|
|
9
|
+
* `frontmatter.$status === "$SUSPEND"`.
|
|
10
|
+
* 2. The persisted StepNode's output node validates as a suspend output
|
|
11
|
+
* (`$status: "$SUSPEND"`, non-empty `reason` carrying the timeout +
|
|
12
|
+
* nativeId), so thread status resolves to `suspended`.
|
|
13
|
+
* 3. `nativeId` / `elapsedMs` are recorded on the detail node for diagnostics.
|
|
14
|
+
* 4. The completed path is unchanged (regression): a `done` stream still
|
|
15
|
+
* extracts frontmatter and reports usage.
|
|
16
|
+
*/
|
|
17
|
+
export {};
|
|
18
|
+
//# sourceMappingURL=e2e-broker-step-suspend.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"e2e-broker-step-suspend.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/e2e-broker-step-suspend.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG"}
|