{"record":{"id":"2ae5d21ec7c2c001","repo":"can1357/oh-my-pi","slug":"prompt-completed-without-a-text-assistant-message","errorCode":null,"errorMessage":"Prompt completed without a text assistant message","messagePattern":"Prompt completed without a text assistant message","errorType":"exception","errorClass":"RpcError","httpStatus":null,"severity":"error","filePath":"python/omp-rpc/src/omp_rpc/client.py","lineNumber":371,"sourceCode":"\n@dataclass(slots=True, frozen=True)\nclass ListenerErrorEvent:\n    listener_kind: str\n    source_type: str | None\n    listener: Callable[..., None]\n    error: BaseException\n\n\n@dataclass(slots=True, frozen=True)\nclass PromptTurn:\n    events: tuple[RpcAgentEvent, ...]\n    messages: tuple[AgentMessage, ...]\n    assistant_message: AssistantMessage | None\n    assistant_text: str | None\n\n    def require_assistant_text(self) -> str:\n        if self.assistant_text is None:\n            raise RpcError(\"Prompt completed without a text assistant message\")\n        return self.assistant_text\n\n\nTodoSeed = str | TodoItem | Mapping[str, object]\nTodoPhaseSeed = TodoPhase | Mapping[str, object]\n\n\n@dataclass(slots=True)\nclass _PendingRequest:\n    command: str\n    response_queue: queue.Queue[JsonObject | BaseException]\n\n\n@dataclass(slots=True)\nclass _PendingHostToolCall:\n    cancel_event: threading.Event\n\n","sourceCodeStart":353,"sourceCodeEnd":389,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/python/omp-rpc/src/omp_rpc/client.py#L353-L389","documentation":"require_assistant_text() is a convenience accessor on the prompt result; it raises when the prompt run finished without producing any assistant message containing text (assistant_text is None). The prompt completed, but no textual reply exists to return.","triggerScenarios":"Calling require_assistant_text() after a prompt that ended in a tool-only turn, an aborted/cancelled run, an error turn, or a model response consisting solely of tool calls with no text.","commonSituations":"Automation that expects every prompt to yield text but the agent stopped after tool execution; aborted sessions due to timeout; model configured to emit only structured/tool output.","solutions":["Inspect result.messages and result.assistant_message first and handle the None case instead of assuming text exists.","Use the full result object (messages, assistant_message) rather than require_assistant_text() when tool-only turns are possible.","Check for aborts/errors in the prompt lifecycle before extracting text.","If the model should always reply with text, adjust the prompt/system instructions to require a final text answer."],"exampleFix":"# before\ntext = result.require_assistant_text()\n\n# after\nif result.assistant_text is None:\n    text = \"(no text reply; last message: \" + str(result.messages[-1] if result.messages else None) + \")\"\nelse:\n    text = result.assistant_text","handlingStrategy":"type-guard","validationCode":"if result.assistant_text is not None:\n    text = result.assistant_text\nelse:\n    text = None","typeGuard":"def has_assistant_text(result) -> bool:\n    return result.assistant_text is not None","tryCatchPattern":"try:\n    text = result.require_assistant_text()\nexcept RpcError as exc:\n    if \"without a text assistant message\" in str(exc):\n        text = \"\"\n    else:\n        raise","preventionTips":["Check assistant_text/messages before requiring text","Design prompts so the model always produces a final text answer","Handle aborted/tool-only turns explicitly in automation"],"tags":["rpc","agent","prompt-lifecycle","missing-result"],"backgroundTag":"prompt-completed-without-text","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}