1import { assert } from "@effect/vitest";
2import type { ProviderReplayTranscript } from "@t3tools/contracts";
3
4import type { OrchestratorV2ScenarioResult } from "../../OrchestratorScenario.ts";
5import {
6 assertSemanticProjectionIntegrity,
7 assertUserMessagesInclude,
8 projectionFor,
9 SUBAGENT_V2_PROMPT,
10} from "../shared.ts";
11
12/**
13 * A Muse native subagent opens a child thread with its prompt and result. Muse
14 * cannot address the child's own session, so the thread shows nothing else and
15 * the result appears exactly once.
16 */
17export function assertMuseSubagentV2Output(
18 result: OrchestratorV2ScenarioResult,
19 transcript: ProviderReplayTranscript,
20) {
21 const projection = projectionFor(result, transcript.scenario);
22 assertSemanticProjectionIntegrity(projection);
23 assertUserMessagesInclude(projection, [SUBAGENT_V2_PROMPT]);
24 assert.deepEqual(
25 projection.runs.map((run) => run.status),
26 ["completed"],
27 );
28 assert.lengthOf(projection.subagents, 1);
29 assert.lengthOf(result.shellSnapshot.threads, 2);
30
31 const subagent = projection.subagents[0]!;
32 assert.equal(subagent.origin, "provider_native");
33 assert.equal(subagent.driver, "muse");
34 assert.equal(subagent.status, "completed");
35 assert.isNotEmpty(subagent.prompt);
36 assert.match(subagent.result ?? "", /^Hello\.?$/u);
37 assert.isNotNull(subagent.completedAt);
38 if (subagent.childThreadId === null) throw new Error("The subagent has no child thread");
39
40 const row = projection.turnItems.find(
41 (item) => item.type === "subagent" && item.subagentId === subagent.id,
42 );
43 assert.equal(row?.type === "subagent" ? row.childThreadId : undefined, subagent.childThreadId);
44
45 const child = result.projections.get(subagent.childThreadId);
46 if (child === undefined) throw new Error("The child thread has no projection");
47 assert.equal(child.thread.lineage.parentThreadId, projection.thread.id);
48 assert.equal(child.thread.lineage.relationshipToParent, "subagent");
49 assert.lengthOf(child.runs, 0);
50 assert.deepEqual(
51 child.messages.map((message) => [message.role, message.text]),
52 [
53 ["user", subagent.prompt],
54 ["assistant", subagent.result],
55 ],
56 );
57 assert.deepEqual(projection.providerThreads[0]?.pendingBackgroundTasks ?? [], []);
58}