{"record":{"id":"59bceed098de982e","repo":"microsoft/autogen","slug":"no-final-model-result-in-streaming-mode","errorCode":null,"errorMessage":"No final model result in streaming mode.","messagePattern":"No final model result in streaming mode\\.","errorType":"exception","errorClass":"RuntimeError","httpStatus":null,"severity":"error","filePath":"python/packages/autogen-agentchat/src/autogen_agentchat/agents/_assistant_agent.py","lineNumber":1106,"sourceCode":"        tools = [tool for wb in workbench for tool in await wb.list_tools()] + handoff_tools\n\n        if model_client_stream:\n            model_result: Optional[CreateResult] = None\n\n            async for chunk in model_client.create_stream(\n                llm_messages,\n                tools=tools,\n                json_output=output_content_type,\n                cancellation_token=cancellation_token,\n            ):\n                if isinstance(chunk, CreateResult):\n                    model_result = chunk\n                elif isinstance(chunk, str):\n                    yield ModelClientStreamingChunkEvent(content=chunk, source=agent_name, full_message_id=message_id)\n                else:\n                    raise RuntimeError(f\"Invalid chunk type: {type(chunk)}\")\n            if model_result is None:\n                raise RuntimeError(\"No final model result in streaming mode.\")\n            yield model_result\n        else:\n            model_result = await model_client.create(\n                llm_messages,\n                tools=tools,\n                cancellation_token=cancellation_token,\n                json_output=output_content_type,\n            )\n            yield model_result\n\n    @classmethod\n    async def _process_model_result(\n        cls,\n        model_result: CreateResult,\n        inner_messages: List[BaseAgentEvent | BaseChatMessage],\n        cancellation_token: CancellationToken,\n        agent_name: str,\n        system_messages: List[SystemMessage],","sourceCodeStart":1088,"sourceCodeEnd":1124,"githubUrl":"https://github.com/microsoft/autogen/blob/027ecf0a379bcc1d09956d46d12d44a3ad9cee14/python/packages/autogen-agentchat/src/autogen_agentchat/agents/_assistant_agent.py#L1088-L1124","documentation":"AssistantAgent raised this after fully consuming model_client.create_stream() without ever receiving a CreateResult chunk. The ChatCompletionClient streaming contract requires string chunks as intermediate deltas and one final CreateResult carrying the complete response; when the stream ends with only deltas, the agent has no final message to add to context or yield.","triggerScenarios":"Running an AssistantAgent with model_client_stream=True where the model client's create_stream() implementation yields only str chunks and returns (typical of hand-rolled or mock clients), or where an internal client error aborts the stream before the final CreateResult.","commonSituations":"Custom ChatCompletionClient implementations (test doubles, replay/proxy clients, thin wrappers) that forget the final CreateResult; buggy or version-mismatched autogen-ext client packages; clients that swallow exceptions and end the generator early.","solutions":["Fix the custom model client so create_stream() yields the complete CreateResult as its final item after all str deltas.","If using a bundled client (autogen-ext), upgrade the autogen-ext package to match the autogen-agentchat version.","Check client logs for swallowed exceptions that terminate the stream before the final result is produced.","As a temporary workaround, construct the AssistantAgent with model_client_stream=False so the non-streaming create() path is used."],"exampleFix":"// before (custom client)\nasync def create_stream(self, messages, **kwargs):\n    async for delta in self._deltas(messages):\n        yield delta  # never yields a final result\n\n// after\nasync def create_stream(self, messages, **kwargs):\n    text = \"\"\n    async for delta in self._deltas(messages):\n        text += delta\n        yield delta\n    yield CreateResult(finish_reason=\"stop\", content=text, usage=..., cached=False)","handlingStrategy":"validation","validationCode":"# Smoke-test the client's streaming contract before wiring it in\nasync def streams_final_result(client) -> bool:\n    chunks = [c async for c in client.create_stream([SystemMessage(content=\"ping\")])]\n    return any(isinstance(c, CreateResult) for c in chunks)\n\nassert await streams_final_result(model_client), \"create_stream must end with a CreateResult\"","typeGuard":null,"tryCatchPattern":"try:\n    async for msg in assistant.run_stream(task=task):\n        ...\nexcept RuntimeError as e:\n    if \"No final model result\" in str(e):\n        # fall back to non-streaming run\n        result = await assistant.run(task=task)\n    else:\n        raise","preventionTips":["Prefer official autogen-ext clients; they implement the str + final CreateResult contract.","Unit-test custom clients against the ChatCompletionClient protocol, including create_stream's final chunk.","Pin autogen-core/agentchat/ext to the same release line."],"tags":["streaming","model-client","assistant-agent","protocol-violation"],"backgroundTag":null,"analyzedSha":"027ecf0a379bcc1d09956d46d12d44a3ad9cee14","analyzedAt":"2026-08-15T03:38:00.719Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}