返回 DeepSeek-Reasonix
transcript-subagent-parent.test.ts
根目录 / desktop / frontend / src / __tests__ / transcript-subagent-parent.test.ts
1 import assert from "node:assert/strict";
2 import test from "node:test";
3 import { ChatSource } from "../lib/chatViewSource";
4 import { TranscriptStore } from "../lib/transcriptStore";
5 import type { HistoryEntry } from "../lib/types";
6 import { FakeBackend } from "./helpers/transcriptFakeBackend";
7
8 const call = (id: string, name: string, parentId?: string) => ({ id, name, arguments: "{}", parentId });
9 const assistant = (n: number, messageId: string, toolCalls: ReturnType<typeof call>[]): HistoryEntry => ({
10 entryId: `m:${messageId}`, turn: 1, order: n, refs: [], message: { role: "assistant", messageId, content: "", toolCalls },
11 });
12 const result = (n: number, toolCallId: string, toolName: string): HistoryEntry => ({
13 entryId: `tool:${toolCallId}`, turn: 1, order: n, refs: [], message: { role: "tool", toolCallId, toolName, content: "ok" },
14 });
15
16 function project(entries: HistoryEntry[]) {
17 const user: HistoryEntry = { entryId: "m:u", turn: 1, order: 0, refs: [], message: { role: "user", messageId: "u", content: "go" } };
18 const store = new TranscriptStore(new FakeBackend([]));
19 return store.installSlice("subagent-parent", "/subagent-parent", {
20 entries: [user, ...entries.map((entry, index) => ({ ...entry, order: index + 1 }))],
21 nextCursor: "", newerCursor: "", hasOlder: false, hasNewer: false, totalTurns: 1, startTurn: 1, endTurn: 1,
22 revision: 1, revisionKnown: true, digest: "subagent-parent", stale: false,
23 });
24 }
25
26 function topLevelTools(items: ReturnType<typeof project>["items"]): string[] {
27 const source = new ChatSource("subagent-parent-view");
28 source.update({ items, localSubmissions: [], running: false, hydrating: false, hasOlder: false, loadingOlder: false });
29 const names = source.getOrderSnapshot().flatMap(key => {
30 const node = source.getNodeSnapshot(key);
31 return node?.kind === "tool" ? [node.item.id] : [];
32 });
33 source.dispose();
34 return names;
35 }
36
37 test("a task sub-agent's own calls keep their parent through the record projection", () => {
38 const projection = project([
39 assistant(1, "parent", [call("task-1", "use_capability")]),
40 assistant(2, "child", [call("task-1/ls1", "ls", "task-1")]),
41 result(3, "task-1/ls1", "ls"),
42 result(4, "task-1", "use_capability"),
43 ]);
44 const child = projection.items.find(item => item.kind === "tool" && item.id === "task-1/ls1");
45 assert.equal(child?.kind === "tool" && child.parentId, "task-1");
46 assert.deepEqual(topLevelTools(projection.items), ["task-1"]);
47 });
48
49 test("a fleet worker's calls nest two levels under the group", () => {
50 const projection = project([
51 assistant(1, "parent", [call("fl", "use_capability")]),
52 assistant(2, "group", [call("fl/fleet-1", "task", "fl")]),
53 assistant(3, "worker", [call("fl/fleet-1/read1", "read_file", "fl/fleet-1")]),
54 result(4, "fl/fleet-1/read1", "read_file"),
55 result(5, "fl/fleet-1", "task"),
56 result(6, "fl", "use_capability"),
57 ]);
58 const parents = new Map(projection.items.flatMap(item => item.kind === "tool" ? [[item.id, item.parentId]] : []));
59 assert.equal(parents.get("fl/fleet-1"), "fl");
60 assert.equal(parents.get("fl/fleet-1/read1"), "fl/fleet-1");
61 assert.deepEqual(topLevelTools(projection.items), ["fl"]);
62 });
63
63 lines TYPESCRIPT