( args: RunLoopArgs, )
| 38 | * with `initialResume` set. |
| 39 | */ |
| 40 | export async function runAgentLoop( |
| 41 | args: RunLoopArgs, |
| 42 | ): Promise<{ iterations: number; interrupted: boolean }> { |
| 43 | const { |
| 44 | agent, |
| 45 | renderer, |
| 46 | tools, |
| 47 | toolDescriptors, |
| 48 | context, |
| 49 | makeToolCtx, |
| 50 | handleInterrupt, |
| 51 | isAborted, |
| 52 | initialResume, |
| 53 | } = args; |
| 54 | const maxIterations = args.maxIterations ?? 6; |
| 55 | const executed = new Set<string>(); |
| 56 | let resume = initialResume; |
| 57 | |
| 58 | for (let i = 0; i < maxIterations; i++) { |
| 59 | if (resume) { |
| 60 | await agent.runAgent( |
| 61 | { forwardedProps: { command: resume } }, |
| 62 | renderer.subscriber, |
| 63 | ); |
| 64 | resume = undefined; |
| 65 | } else { |
| 66 | await agent.runAgent( |
| 67 | { tools: toolDescriptors as never, context: context as never }, |
| 68 | renderer.subscriber, |
| 69 | ); |
| 70 | } |
| 71 | if (isAborted?.()) return { iterations: i + 1, interrupted: false }; |
| 72 | |
| 73 | const pending = renderer.getPendingInterrupt(); |
| 74 | if (pending) { |
| 75 | renderer.clearPendingInterrupt(); |
| 76 | if (handleInterrupt) await handleInterrupt(pending); |
| 77 | // ack-first: picker posted; thread.resume re-enters later |
| 78 | return { iterations: i + 1, interrupted: true }; |
| 79 | } |
| 80 | |
| 81 | const calls = renderer |
| 82 | .getCapturedToolCalls() |
| 83 | .filter((c) => tools.has(c.toolCallName) && !executed.has(c.toolCallId)); |
| 84 | if (calls.length === 0) return { iterations: i + 1, interrupted: false }; |
| 85 | |
| 86 | ensureAssistantToolCallMessage(agent, calls); |
| 87 | for (const call of calls) { |
| 88 | const tool = tools.get(call.toolCallName)!; |
| 89 | let result: string; |
| 90 | const parsed = await parseToolArgs(tool.parameters, call.toolCallArgs); |
| 91 | if (!parsed.ok) { |
| 92 | result = JSON.stringify({ |
| 93 | error: `invalid arguments: ${parsed.error}`, |
| 94 | }); |
| 95 | } else { |
| 96 | try { |
| 97 | result = stringifyHandlerResult( |
no test coverage detected
searching dependent graphs…