{"record":{"id":"77cd0c1a23a272de","repo":"earendil-works/pi","slug":"agent-is-already-processing-wait-for-completion-b-77cd0c","errorCode":null,"errorMessage":"Agent is already processing. Wait for completion before continuing.","messagePattern":"Agent is already processing\\. Wait for completion before continuing\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/agent/src/agent.ts","lineNumber":363,"sourceCode":"\t}\n\n\t/** Start a new prompt from text, a single message, or a batch of messages. */\n\tasync prompt(message: AgentMessage | AgentMessage[]): Promise<void>;\n\tasync prompt(input: string, images?: ImageContent[]): Promise<void>;\n\tasync prompt(input: string | AgentMessage | AgentMessage[], images?: ImageContent[]): Promise<void> {\n\t\tif (this.activeRun) {\n\t\t\tthrow new Error(\n\t\t\t\t\"Agent is already processing a prompt. Use steer() or followUp() to queue messages, or wait for completion.\",\n\t\t\t);\n\t\t}\n\t\tconst messages = this.normalizePromptInput(input, images);\n\t\tawait this.runPromptMessages(messages);\n\t}\n\n\t/** Continue from the current transcript. The last message must be a user or tool-result message. */\n\tasync continue(): Promise<void> {\n\t\tif (this.activeRun) {\n\t\t\tthrow new Error(\"Agent is already processing. Wait for completion before continuing.\");\n\t\t}\n\n\t\tconst lastMessage = this._state.messages[this._state.messages.length - 1];\n\t\tif (!lastMessage) {\n\t\t\tthrow new Error(\"No messages to continue from\");\n\t\t}\n\n\t\tif (lastMessage.role === \"assistant\") {\n\t\t\tconst queuedSteering = this.steeringQueue.drain();\n\t\t\tif (queuedSteering.length > 0) {\n\t\t\t\tawait this.runPromptMessages(queuedSteering, { skipInitialSteeringPoll: true });\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\tconst queuedFollowUps = this.followUpQueue.drain();\n\t\t\tif (queuedFollowUps.length > 0) {\n\t\t\t\tawait this.runPromptMessages(queuedFollowUps);\n\t\t\t\treturn;","sourceCodeStart":345,"sourceCodeEnd":381,"githubUrl":"https://github.com/earendil-works/pi/blob/4af9d21d3b4d664e4a29fcabfec85171077248e3/packages/agent/src/agent.ts#L345-L381","documentation":"Agent.continue() resumes an idle agent from its transcript; like prompt() and reset() it is an idle-only operation and rejects while activeRun exists. The single-run design means a continuation cannot be started on top of a run that is still streaming or still settling its agent_end listeners. steer() and followUp() are the concurrency-safe ways to add input while a run is active.","triggerScenarios":"Calling agent.continue() while a prompt()/continue() run is in flight; auto-continue loops that fire on a timer without checking idle; calling continue() from an event listener that executes before the run's agent_end listeners settle.","commonSituations":"Orchestrators that continue after each turn in a while-loop without awaiting; retry schedulers; UI resume buttons racing an in-progress run.","solutions":["await agent.waitForIdle() before calling continue().","If you wanted to inject input mid-run, use steer()/followUp() - continue() is only for resuming an idle agent.","Await each prompt()/continue() fully (including listener settlement) before scheduling the next."],"exampleFix":"// before\nvoid agent.prompt(\"hi\");\nawait agent.continue(); // rejects: previous run still active\n\n// after\nawait agent.prompt(\"hi\");\nawait agent.waitForIdle();\nawait agent.continue();","handlingStrategy":"validation","validationCode":"await agent.waitForIdle(); // no-op when idle\nawait agent.continue();","typeGuard":null,"tryCatchPattern":"try {\n  await agent.continue();\n} catch (err) {\n  if (err instanceof Error && err.message.includes(\"before continuing\")) {\n    await agent.waitForIdle();\n    await agent.continue(); // retry once the run settled\n  } else {\n    throw err;\n  }\n}","preventionTips":["Never schedule continue() from a timer without checking idle first.","Await each run fully, including agent_end listener settlement.","Use steer()/followUp() for mid-run input instead of continue()."],"tags":["agent","continue","concurrency","race-condition"],"backgroundTag":"agent-busy-concurrent-call","analyzedSha":"4af9d21d3b4d664e4a29fcabfec85171077248e3","analyzedAt":"2026-08-24T13:07:14.692Z","schemaVersion":2},"datasetVersion":"2026-08-24T17:17:21.512Z"}