fix(agent): validate context/memory tool schemas before wrapping (#47707) - #52140
Conversation
Closes #47707 Context engines and memory providers expose tool schemas via get_tool_schemas(). agent_init.py wrapped each as {"type":"function","function":_schema} without validating that _schema carries a top-level name. A provider returning an entry already in OpenAI tool form ({"type":"function","function":{...}}) was then double-wrapped into a tool whose function has no name. Strict providers (e.g. DeepSeek) reject the entire request with HTTP 400 'tools[N].function: missing field name', so one malformed schema silently disables the whole toolset and breaks every turn. The schema was also never added to valid_tool_names, so even lenient providers could not call it. Add a shared normalize_tool_schema() helper that unwraps an already-wrapped entry and returns None for anything lacking a resolvable string name. Wire it into the agent_init context-engine loop and all three memory_manager surfaces (inject_memory_provider_tools, add_provider routing index, get_all_tool_schemas), so a single bad plugin schema is skipped with a warning instead of poisoning the request. Verification: 209 targeted agent/memory tests pass (incl. 9 new). New tests assert the unwrap + skip-nameless behavior and fail without the fix.
🔎 Lint report:
|
Related: this is a salvage of #47712 (@Bartok9) for issue #47707, which has a saturated competing-fix cluster: #47712 (same files/scope), #47721 (context-engine-only), #47732 (unwrap variant), #48065 (agent_init.py-only subset). #49437 was already closed as a dup of #47712. Flagging for a maintainer to pick the canonical PR; the |
|
Thanks for the triage map @alt-glitch — happy to consolidate. Quick case for this one as canonical:
Salvaged from #47712. If a maintainer prefers I rebase onto a different base or fold in anything from #47732's variant, glad to do it. |
…-tool-schema-validation fix(agent): validate context/memory tool schemas before wrapping (NousResearch#47707)
…-tool-schema-validation fix(agent): validate context/memory tool schemas before wrapping (NousResearch#47707)
…-tool-schema-validation fix(agent): validate context/memory tool schemas before wrapping (NousResearch#47707)
…-tool-schema-validation fix(agent): validate context/memory tool schemas before wrapping (NousResearch#47707)
…-tool-schema-validation fix(agent): validate context/memory tool schemas before wrapping (NousResearch#47707)
Summary
One malformed tool schema from a context engine or memory provider no longer disables the entire toolset with an HTTP 400 from strict providers like DeepSeek.
Root cause
agent_init.pywrapped each schema fromget_tool_schemas()as{"type": "function", "function": _schema}without validating that_schemahas a top-levelname. A provider returning an already-wrapped entry ({"type":"function","function":{...}}) would be double-wrapped into a nameless tool. Strict providers reject the entire request withtools[N].function: missing field name(HTTP 400), breaking every turn.Changes
agent/memory_manager.py: sharednormalize_tool_schema()helper that unwraps already-wrapped entries and returns None for nameless schemas. Wired into all 4 call sites: agent_init context-engine loop + 3 memory_manager surfaces (inject_memory_provider_tools, add_provider routing, get_all_tool_schemas)agent/agent_init.py: usesnormalize_tool_schema()in the context-engine tool injection looptests/agent/test_memory_provider.py: 9 new tests (unwrap, skip-nameless, non-dict, non-string-name, good+bad alongside, real injection path)Validation
Salvaged from #47712 by @Bartok9.
Closes #47707