can1357/oh-my-pi · error

Cannot continue from message role: assistant

Error message

Cannot continue from message role: assistant

What it means

Agent.continue() throws this when the last message in the transcript has role "assistant" but the tail contains no unpaired runnable tool calls and no steering/follow-up messages are queued (packages/agent/src/agent.ts:1274). A completed assistant turn is a natural stopping point: there is no pending tool result to feed back and no new user input, so the loop cannot decide what to generate next. Continuation is only valid from a user/tool tail or an assistant tail mid tool-execution.

Source

Thrown at packages/agent/src/agent.ts:1274

				// blocks and their results would break the provider's pairing
				// invariant. Queued messages drain inside the resumed loop instead.
				if (unpairedToolCallTail(messages)) {
					await this.#runLoop(undefined, undefined, signal, true);
					return;
				}
				const queuedSteering = await this.#dequeueSteeringMessagesAfterHooks(dequeueSignal);
				if (queuedSteering.length > 0) {
					await this.#runLoop(queuedSteering, { skipInitialSteeringPoll: true }, signal, true);
					return;
				}

				const queuedFollowUp = await this.#dequeueFollowUpMessagesAfterHooks(dequeueSignal);
				if (queuedFollowUp.length > 0) {
					await this.#runLoop(queuedFollowUp, undefined, signal, true);
					return;
				}

				throw new Error("Cannot continue from message role: assistant");
			}

			await this.#runLoop(undefined, undefined, signal, true);
		} finally {
			resolve();
			if (this.#abortController === continuationAbortController) {
				this.#state.isStreaming = false;
				this.#state.streamMessage = null;
				this.#state.pendingToolCalls.clear();
				this.#abortController = undefined;
				if (this.#runningPrompt === promise) {
					this.#runningPrompt = undefined;
					this.#resolveRunningPrompt = undefined;
				}
			}
		}
	}

View on GitHub (pinned to 9690622007)

Solutions

  1. Send a new user message with prompt() or queue one with followUp() instead of calling continue() — a finished assistant turn needs new input.
  2. Check the last message role before continuing: only continue when the tail is a user/tool message or an assistant message with unpaired tool calls.
  3. If your drain loop calls continue() repeatedly, stop when the turn completed and nothing is queued (the error signals that state).
  4. If you expected tool calls to be pending, verify the run didn't already complete them before the interruption.

Example fix

// before
await agent.continue(); // throws when last message is a final assistant reply

// after
const msgs = getMessages(agent);
const last = msgs[msgs.length - 1];
if (last?.role === "assistant") {
  agent.followUp("please proceed");
} else {
  await agent.continue();
}
Defensive patterns

Strategy: validation

Validate before calling

function continueIsMeaningful(agent: Agent): boolean {
  const msgs = getMessages(agent);
  const last = msgs[msgs.length - 1];
  if (!last) return false;
  if (last.role !== "assistant") return true;
  return hasQueuedMessages(agent) || hasUnpairedToolCalls(msgs);
}
if (continueIsMeaningful(agent)) await agent.continue();

Try / catch

try {
  await agent.continue();
} catch (err) {
  if (err instanceof Error && err.message.startsWith("Cannot continue from message role")) {
    agent.followUp("please proceed with the next step");
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Calling continue() right after a normal assistant reply finished (turn completed cleanly); resuming a session whose transcript ends with a final assistant answer; an idle-drain loop re-invoking continue() after the agent already answered with nothing queued.

Common situations: Auto-continue/retry schedulers that keep calling continue() after every completed turn; loading a saved session that ended on a complete assistant message and attempting to resume it; confusion between 'continue the conversation' (use prompt/followUp) and 'resume interrupted work' (continue).

Related errors


AI-assisted analysis of can1357/oh-my-pi@9690622007 (2026-08-31). Data as JSON: /api/errors/4ed263fbf0e42af5. Report an issue: GitHub.