* Emit nested tool events from PTC code_execution. * These are forwarded to the frontend via the same event channel as regular tool events. * The parentToolCallId field identifies which code_execution call spawned this nested call. * * Also persists nested calls to streamInfo.parts so th
(
workspaceId: string,
messageId: string,
event: {
type: "tool-call-start" | "tool-call-end";
callId: string;
toolName: string;
args: unknown;
parentToolCallId: string;
startTime: number;
endTime?: number;
result?: unknown;
error?: string;
}
)
| 1797 | * Also persists nested calls to streamInfo.parts so they survive interruption/reload. |
| 1798 | */ |
| 1799 | emitNestedToolEvent( |
| 1800 | workspaceId: string, |
| 1801 | messageId: string, |
| 1802 | event: { |
| 1803 | type: "tool-call-start" | "tool-call-end"; |
| 1804 | callId: string; |
| 1805 | toolName: string; |
| 1806 | args: unknown; |
| 1807 | parentToolCallId: string; |
| 1808 | startTime: number; |
| 1809 | endTime?: number; |
| 1810 | result?: unknown; |
| 1811 | error?: string; |
| 1812 | } |
| 1813 | ): void { |
| 1814 | // Persist nested calls to streamInfo.parts for crash/interrupt resilience |
| 1815 | const streamInfo = this.workspaceStreams.get(workspaceId as WorkspaceId); |
| 1816 | if (streamInfo) { |
| 1817 | const parentPartIndex = streamInfo.parts.findIndex( |
| 1818 | (p): p is CompletedMessagePart & { type: "dynamic-tool"; toolCallId: string } => |
| 1819 | p.type === "dynamic-tool" && "toolCallId" in p && p.toolCallId === event.parentToolCallId |
| 1820 | ); |
| 1821 | |
| 1822 | if (parentPartIndex !== -1) { |
| 1823 | const parentPart = streamInfo.parts[parentPartIndex] as { nestedCalls?: NestedToolCall[] }; |
| 1824 | const nestedCalls = parentPart.nestedCalls ?? []; |
| 1825 | |
| 1826 | if (event.type === "tool-call-start") { |
| 1827 | nestedCalls.push({ |
| 1828 | toolCallId: event.callId, |
| 1829 | toolName: event.toolName, |
| 1830 | input: event.args, |
| 1831 | state: "input-available", |
| 1832 | timestamp: event.startTime, |
| 1833 | }); |
| 1834 | } else if (event.type === "tool-call-end") { |
| 1835 | const idx = nestedCalls.findIndex((n) => n.toolCallId === event.callId); |
| 1836 | if (idx !== -1) { |
| 1837 | nestedCalls[idx] = { |
| 1838 | ...nestedCalls[idx], |
| 1839 | output: event.result ?? (event.error ? { error: event.error } : undefined), |
| 1840 | state: "output-available", |
| 1841 | }; |
| 1842 | } |
| 1843 | } |
| 1844 | |
| 1845 | parentPart.nestedCalls = nestedCalls; |
| 1846 | |
| 1847 | // Schedule partial write so nested calls survive crashes |
| 1848 | void this.schedulePartialWrite(workspaceId as WorkspaceId, streamInfo); |
| 1849 | } |
| 1850 | } |
| 1851 | |
| 1852 | // Emit to frontend |
| 1853 | if (event.type === "tool-call-start") { |
| 1854 | this.emit("tool-call-start", { |
| 1855 | type: "tool-call-start", |
| 1856 | workspaceId, |
no test coverage detected