Skip to content

Commit a9fdee4

Browse files
refactor(boundaries): split final dense helpers
1 parent 9d932f9 commit a9fdee4

6 files changed

Lines changed: 244 additions & 177 deletions

File tree

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import type { SDKMessage } from "@anthropic-ai/claude-agent-sdk";
2+
3+
import type { RunActor } from "../../../../shared/agent-runtime/events.js";
4+
import type { ClaudeTraceState } from "./types.js";
5+
6+
export function rootClaudeActor(sessionId: string | undefined): RunActor {
7+
return {
8+
threadId: sessionId ?? null,
9+
role: sessionId === undefined ? "unknown" : "root",
10+
confidence: sessionId === undefined ? "unknown" : "provider",
11+
label: sessionId === undefined ? "Unknown actor" : "Main",
12+
};
13+
}
14+
15+
export function getClaudeSessionId(message: SDKMessage): string | undefined {
16+
return "session_id" in message && typeof message.session_id === "string"
17+
? message.session_id
18+
: undefined;
19+
}
20+
21+
export function actorForClaudeMessage(
22+
message: SDKMessage,
23+
trace: ClaudeTraceState,
24+
): RunActor {
25+
const sessionId = getClaudeSessionId(message) ?? trace.sessionId;
26+
trace.sessionId = trace.sessionId ?? sessionId;
27+
const parentToolUseId = parentToolUseIdFromClaudeMessage(message);
28+
if (parentToolUseId === null) {
29+
return rootClaudeActor(sessionId);
30+
}
31+
rememberClaudeHelper(trace, parentToolUseId, sessionId ?? null);
32+
return {
33+
threadId: parentToolUseId,
34+
role: "helper",
35+
parentThreadId: trace.agentParents[parentToolUseId] ?? null,
36+
confidence: "derived",
37+
label: trace.agentLabels[parentToolUseId],
38+
};
39+
}
40+
41+
export function actorForClaudeHelper(
42+
trace: ClaudeTraceState,
43+
toolUseId: string,
44+
): RunActor {
45+
return {
46+
threadId: toolUseId,
47+
role: "helper",
48+
parentThreadId: trace.agentParents[toolUseId] ?? trace.sessionId ?? null,
49+
confidence: "derived",
50+
label: trace.agentLabels[toolUseId] ?? helperLabel(trace, toolUseId),
51+
};
52+
}
53+
54+
export function parentToolUseIdFromClaudeMessage(
55+
message: SDKMessage,
56+
): string | null {
57+
if (!("parent_tool_use_id" in message)) return null;
58+
const value = message.parent_tool_use_id;
59+
return typeof value === "string" && value.length > 0 ? value : null;
60+
}
61+
62+
export function rememberClaudeHelper(
63+
trace: ClaudeTraceState,
64+
toolUseId: string,
65+
parentThreadId: string | null,
66+
): void {
67+
trace.agentParents[toolUseId] = trace.agentParents[toolUseId] ?? parentThreadId;
68+
trace.agentLabels[toolUseId] =
69+
trace.agentLabels[toolUseId] ?? helperLabel(trace, toolUseId);
70+
}
71+
72+
function helperLabel(trace: ClaudeTraceState, id: string): string {
73+
const existing = trace.agentLabels[id];
74+
if (existing !== undefined) return existing;
75+
const label = `Helper ${Object.keys(trace.agentLabels).length + 1}`;
76+
trace.agentLabels[id] = label;
77+
return label;
78+
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
export function stringifyClaudeToolResult(content: unknown): string {
2+
if (typeof content === "string") return content;
3+
return stringifyClaudeInput(content) ?? "";
4+
}
5+
6+
export function promptFromClaudeAgentInput(input: unknown): string {
7+
if (input !== null && typeof input === "object") {
8+
const prompt = (input as { prompt?: unknown }).prompt;
9+
if (typeof prompt === "string") return prompt;
10+
const description = (input as { description?: unknown }).description;
11+
if (typeof description === "string") return description;
12+
}
13+
return "";
14+
}
15+
16+
export function textDeltaFromClaudeStreamEvent(event: unknown): string | undefined {
17+
if (event === null || typeof event !== "object") return undefined;
18+
const raw = event as {
19+
type?: unknown;
20+
delta?: { type?: unknown; text?: unknown };
21+
};
22+
return raw.type === "content_block_delta" &&
23+
raw.delta?.type === "text_delta" &&
24+
typeof raw.delta.text === "string"
25+
? raw.delta.text
26+
: undefined;
27+
}
28+
29+
export function stringifyClaudeInput(input: unknown): string | undefined {
30+
if (input === undefined) return undefined;
31+
if (typeof input === "string") return input;
32+
try {
33+
return JSON.stringify(input);
34+
} catch {
35+
return String(input);
36+
}
37+
}
Lines changed: 22 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,21 @@
11
import type { SDKMessage } from "@anthropic-ai/claude-agent-sdk";
22

33
import type { AgentRuntimeEvent } from "../../../../shared/agent-runtime/events.js";
4-
import type { RunActor } from "../../../../shared/agent-runtime/events.js";
54
import type { ClaudeTraceState } from "./types.js";
5+
import {
6+
actorForClaudeHelper,
7+
actorForClaudeMessage,
8+
parentToolUseIdFromClaudeMessage,
9+
rememberClaudeHelper,
10+
} from "./actors.js";
11+
import {
12+
promptFromClaudeAgentInput,
13+
stringifyClaudeInput,
14+
stringifyClaudeToolResult,
15+
textDeltaFromClaudeStreamEvent,
16+
} from "./content.js";
17+
18+
export { getClaudeSessionId, rootClaudeActor } from "./actors.js";
619

720
export function toClaudeAgentRuntimeEvents(
821
message: SDKMessage,
@@ -14,7 +27,7 @@ export function toClaudeAgentRuntimeEvents(
1427
): AgentRuntimeEvent[] {
1528
const actor = actorForClaudeMessage(message, trace);
1629
if (message.type === "stream_event") {
17-
const text = getTextDelta(message.event);
30+
const text = textDeltaFromClaudeStreamEvent(message.event);
1831
return text !== undefined ? [{ type: "text_delta", content: text, actor }] : [];
1932
}
2033

@@ -32,14 +45,14 @@ export function toClaudeAgentRuntimeEvents(
3245
type: "tool_use",
3346
id: block.id,
3447
tool: block.name,
35-
input: stringifyInput(block.input),
48+
input: stringifyClaudeInput(block.input),
3649
actor,
3750
providerEventId: message.uuid,
38-
providerParentToolUseId: parentToolUseIdFromMessage(message) ?? undefined,
51+
providerParentToolUseId:
52+
parentToolUseIdFromClaudeMessage(message) ?? undefined,
3953
});
4054
if (block.name === "Agent") {
41-
trace.agentParents[block.id] = trace.sessionId ?? null;
42-
trace.agentLabels[block.id] = helperLabel(trace, block.id);
55+
rememberClaudeHelper(trace, block.id, trace.sessionId ?? null);
4356
events.push({
4457
type: "agent_spawned",
4558
parentThreadId: trace.sessionId ?? "",
@@ -66,7 +79,8 @@ export function toClaudeAgentRuntimeEvents(
6679
isError: block.is_error,
6780
actor,
6881
providerEventId: message.uuid,
69-
providerParentToolUseId: parentToolUseIdFromMessage(message) ?? undefined,
82+
providerParentToolUseId:
83+
parentToolUseIdFromClaudeMessage(message) ?? undefined,
7084
},
7185
];
7286
if (
@@ -80,7 +94,7 @@ export function toClaudeAgentRuntimeEvents(
8094
threadId: block.tool_use_id,
8195
parentThreadId:
8296
trace.agentParents[block.tool_use_id] ?? trace.sessionId ?? null,
83-
result: stringifyToolResult(block.content),
97+
result: stringifyClaudeToolResult(block.content),
8498
actor: helperActor,
8599
});
86100
}
@@ -98,103 +112,3 @@ export function toClaudeAgentRuntimeEvents(
98112

99113
return [];
100114
}
101-
102-
export function rootClaudeActor(sessionId: string | undefined): RunActor {
103-
return {
104-
threadId: sessionId ?? null,
105-
role: sessionId === undefined ? "unknown" : "root",
106-
confidence: sessionId === undefined ? "unknown" : "provider",
107-
label: sessionId === undefined ? "Unknown actor" : "Main",
108-
};
109-
}
110-
111-
export function getClaudeSessionId(message: SDKMessage): string | undefined {
112-
return "session_id" in message && typeof message.session_id === "string"
113-
? message.session_id
114-
: undefined;
115-
}
116-
117-
function actorForClaudeMessage(
118-
message: SDKMessage,
119-
trace: ClaudeTraceState,
120-
): RunActor {
121-
const sessionId = getClaudeSessionId(message) ?? trace.sessionId;
122-
trace.sessionId = trace.sessionId ?? sessionId;
123-
const parentToolUseId = parentToolUseIdFromMessage(message);
124-
if (parentToolUseId === null) {
125-
return rootClaudeActor(sessionId);
126-
}
127-
trace.agentParents[parentToolUseId] =
128-
trace.agentParents[parentToolUseId] ?? sessionId ?? null;
129-
trace.agentLabels[parentToolUseId] =
130-
trace.agentLabels[parentToolUseId] ?? helperLabel(trace, parentToolUseId);
131-
return {
132-
threadId: parentToolUseId,
133-
role: "helper",
134-
parentThreadId: trace.agentParents[parentToolUseId] ?? null,
135-
confidence: "derived",
136-
label: trace.agentLabels[parentToolUseId],
137-
};
138-
}
139-
140-
function actorForClaudeHelper(trace: ClaudeTraceState, toolUseId: string): RunActor {
141-
return {
142-
threadId: toolUseId,
143-
role: "helper",
144-
parentThreadId: trace.agentParents[toolUseId] ?? trace.sessionId ?? null,
145-
confidence: "derived",
146-
label: trace.agentLabels[toolUseId] ?? helperLabel(trace, toolUseId),
147-
};
148-
}
149-
150-
function stringifyToolResult(content: unknown): string {
151-
if (typeof content === "string") return content;
152-
return stringifyInput(content) ?? "";
153-
}
154-
155-
function parentToolUseIdFromMessage(message: SDKMessage): string | null {
156-
if (!("parent_tool_use_id" in message)) return null;
157-
const value = message.parent_tool_use_id;
158-
return typeof value === "string" && value.length > 0 ? value : null;
159-
}
160-
161-
function helperLabel(trace: ClaudeTraceState, id: string): string {
162-
const existing = trace.agentLabels[id];
163-
if (existing !== undefined) return existing;
164-
const label = `Helper ${Object.keys(trace.agentLabels).length + 1}`;
165-
trace.agentLabels[id] = label;
166-
return label;
167-
}
168-
169-
function promptFromClaudeAgentInput(input: unknown): string {
170-
if (input !== null && typeof input === "object") {
171-
const prompt = (input as { prompt?: unknown }).prompt;
172-
if (typeof prompt === "string") return prompt;
173-
const description = (input as { description?: unknown }).description;
174-
if (typeof description === "string") return description;
175-
}
176-
return "";
177-
}
178-
179-
function getTextDelta(event: unknown): string | undefined {
180-
if (event === null || typeof event !== "object") return undefined;
181-
const raw = event as {
182-
type?: unknown;
183-
delta?: { type?: unknown; text?: unknown };
184-
};
185-
return raw.type === "content_block_delta" &&
186-
raw.delta?.type === "text_delta" &&
187-
typeof raw.delta.text === "string"
188-
? raw.delta.text
189-
: undefined;
190-
}
191-
192-
function stringifyInput(input: unknown): string | undefined {
193-
if (input === undefined) return undefined;
194-
if (typeof input === "string") return input;
195-
try {
196-
return JSON.stringify(input);
197-
} catch {
198-
return String(input);
199-
}
200-
}

0 commit comments

Comments
 (0)