发布

  • fix(llm): normalize str-returns to a message in the central LLM wrapper (+ ainvoke) (#4342)

    frostbyte_neo 发布于 2026-05-25 14:47:11 +00:00

    • fix(llm): normalize str-returns to a message in ProcessingLLMWrapper + add ainvoke

    The central wrapper (returned by all get_llm paths) stripped tags but
    returned a bare str when the base LLM returned a str — that inconsistent shape is
    the root of the recurring "'str' object has no attribute 'content'" crashes we've
    been fixing site-by-site (#3884 -> #4339).

    Generic fix at the choke point:

    • invoke(): when the base returns a bare str, wrap it into AIMessage(content=stripped)
      instead of returning a str. Message returns are unchanged (mutate .content in place,
      preserving additional_kwargs/reasoning_content/tool_calls). Other types pass through.
    • add ainvoke(): mirrors invoke(); without it, the 7 direct .ainvoke() sites
      (browsecomp_entity/modular strategies) bypassed think-stripping via getattr.

    Now every get_llm LLM yields a think-free str .content on both sync and async direct
    calls, so the raw .invoke().content sites are safe automatically (deferred per-site
    migration cancelled). Reasoning-safe: only .content is rewritten, so DeepSeek
    thinking-mode reasoning_content round-tripping (#4194) is not worsened.

    Limitation: the LangGraph create_agent path binds tools on the base model
    (model.bind_tools via getattr), so it bypasses this wrapper — unchanged by this PR.

    Tests: updated the 2 tests asserting a str return; added shape, reasoning_content/
    tool_calls-preservation (#4194 guard), and ainvoke regression tests.
    mypy 552 clean; ruff clean; 2171 passed across 78 LLM-layer test files + citation_handlers.

    • refactor(llm): extract _log_llm_error helper + add type hints (review polish)

    Addresses the #4342 review recommendations:

    • DRY: invoke() and ainvoke() shared the same try/except error-logging verbatim;
      extracted a _log_llm_error(error) static helper so they can't diverge.
    • Type hints: added annotations to _normalize_response/_log_llm_error/invoke/ainvoke.
      No behavior change. ruff + mypy clean; 112 config tests pass.
    下载附件