{"record":{"id":"3fae3a8381cbc739","repo":"zylon-ai/private-gpt","slug":"expected-tool-calls-in-response-but-found-none-me","errorCode":null,"errorMessage":"Expected tool calls in response but found none. Message: {response.message}","messagePattern":"Expected tool calls in response but found none\\. Message: (.+?)","errorType":"exception","errorClass":"ValueError","httpStatus":null,"severity":"error","filePath":"private_gpt/components/llm/custom/openairesponses.py","lineNumber":224,"sourceCode":"        never accumulates blocks — it stores ToolCallBlock objects in\n        message.additional_kwargs[\"tool_calls\"] instead.  We check both locations.\n        \"\"\"\n        from llama_index.core.llms.llm import ToolSelection\n        from llama_index.core.llms.utils import parse_partial_json\n\n        # Non-streaming / ResponseCompletedEvent path: blocks populated directly\n        tool_call_blocks = [\n            b for b in response.message.blocks if isinstance(b, ToolCallBlock)\n        ]\n\n        # Streaming accumulation path: _handle_stream_chunk stores them here\n        if not tool_call_blocks:\n            raw = response.message.additional_kwargs.get(\"tool_calls\", [])\n            tool_call_blocks = [tc for tc in raw if isinstance(tc, ToolCallBlock)]\n\n        if not tool_call_blocks:\n            if error_on_no_tool_call:\n                raise ValueError(\n                    \"Expected tool calls in response but found none. \"\n                    f\"Message: {response.message}\"\n                )\n            return []\n\n        tool_selections = []\n        for b in tool_call_blocks:\n            # tool_kwargs may be a JSON string (Responses API) or already a dict\n            raw_kwargs = b.tool_kwargs\n            if isinstance(raw_kwargs, str):\n                try:\n                    argument_dict = parse_partial_json(raw_kwargs) or {}\n                except Exception:\n                    argument_dict = {}\n            else:\n                argument_dict = raw_kwargs or {}\n            tool_selections.append(\n                ToolSelection(","sourceCodeStart":206,"sourceCodeEnd":242,"githubUrl":"https://github.com/zylon-ai/private-gpt/blob/4a030776a31a901ad80b1bf4d7faa2c1a367efbb/private_gpt/components/llm/custom/openairesponses.py#L206-L242","documentation":"ValueError raised while extracting tool calls from an OpenAI Responses LLM result when no ToolCallBlock is present in message.blocks nor in additional_kwargs['tool_calls'], and error_on_no_tool_call is enabled. It means the model answered with plain content instead of invoking a function/tool, and the caller declared that a tool call was mandatory.","triggerScenarios":"Using OpenAIResponses-based agents/structured output where the prompt or function-calling config expects a tool call, but the model returns a text response — weak function-calling models, missing tools in the request, schema the model rejects, or the model asking a clarifying question.","commonSituations":"Switching to a model with poor function-calling support; tool definitions omitted from the chat request; overly complex JSON schema the model refuses; temperature/max_tokens settings truncating the response before the tool call is emitted.","solutions":["Log response.message to see what the model said instead of calling the tool — often a clarification or refusal you can address in the prompt.","Ensure tools are actually attached to the request and the schema is valid JSON Schema the model supports.","Use a model with reliable function calling (per the Responses API docs) for tool-driven flows.","If a text answer is acceptable in some cases, disable error_on_no_tool_call and handle the empty selection list."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try:\n    selections = extract_tool_selections(response, error_on_no_tool_call=True)\nexcept ValueError as e:\n    if 'Expected tool calls' in str(e):\n        logger.warning('model declined tool call: %s', response.message.content)\n        selections = []  # fall back to plain-answer handling","preventionTips":["Verify tools are attached and schemas are valid before relying on mandatory tool calls.","Prefer models with strong function-calling support; log refusals to detect prompt/schema problems early."],"tags":["llm","openai","function-calling","tools","agent"],"backgroundTag":null,"analyzedSha":"4a030776a31a901ad80b1bf4d7faa2c1a367efbb","analyzedAt":"2026-08-15T03:51:26.951Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}