fix(openai-compatible): send list tool return as native list content - #398
fix(openai-compatible): send list tool return as native list content#398Million-mo wants to merge 1 commit into
Conversation
Code Review — PR #398Reviewed the diff against the pinned Important
Minor
Docs
Verified positives
|
|
Posted the synthesized review: #398 (comment) Summary of findings: Verified (ran in sandbox against pinned pydantic-ai 2.17.0): 13/13 tests pass, ruff clean, mypy --strict clean on the new module, and the Key findings:
|
Subclass OpenAIChatModel as OpenAICompatibleModel to send list-type ToolReturnPart content as native list[ChatCompletionContentPartTextParam] instead of a JSON-serialized string. This fixes compatibility with OpenAI-compatible models (e.g. GLM-5) whose chat templates branch on tool role content being a string vs list. All OpenAI-compatible providers (deepseek:, grok:, openrouter:, perplexity:, lm-studio:, zen:, copilot:) now use OpenAICompatibleModel. Non-list content, multimodal files, and failed tool returns fall back to the parent's string serialization. Closes #112
61c56fe to
03208ef
Compare

Problem
pydantic-ai's
OpenAIChatModelalways serializes list-typeToolReturnPartcontent as a JSON string, instead of using the OpenAI SDK's nativelist[ChatCompletionContentPartTextParam]format.This breaks OpenAI-compatible models (e.g. GLM-5) whose chat templates branch on
toolrolecontentbeing a string vs list:<|tool_return|>block with escaped JSON text<|tool_return|>blocks, each with a native resultCloses #112.
Solution
Subclass
OpenAIChatModelasOpenAICompatibleModel, overriding_map_user_messageto send list content as nativelist[ChatCompletionContentPartTextParam]when:ToolReturnPart.contentis alistAll other cases (string/dict/int content, multimodal files, failed returns) fall back to the parent's string serialization.
Affected providers
All OpenAI-compatible providers now use
OpenAICompatibleModel:deepseek:grok:openrouter:perplexity:lm-studio:zen:copilot:openai:(Responses API) andopenai-chat:(pydantic-ai built-in) are unaffected.Changes
src/wolfharness/models/openai_compatible.py—OpenAICompatibleModelclasssrc/wolfharness/utils/model_helpers.py— useOpenAICompatibleModelin_get_openai_based_model()andcopilot:prefixtests/unit/test_openai_compatible_model.py— 13 unit testschangelog/unreleased/2026-08-28-openai-compatible-tool-return-list-content.mdVerification