fix(tools): never crash list_tools on string or exotic annotations#35
Merged
Conversation
PythonToolProvider._function_to_tool called param.annotation.__name__, which raises AttributeError whenever the tool module uses from __future__ import annotations or quoted annotations (the annotation is then a str), or any typing construct without a usable __name__. One such tool function bricked the whole agent: list_tools runs on every message, so the AttributeError surfaced as a 500 on every chat request. Map string annotations directly (so future-import modules produce the same schemas as normal ones via the existing str/int mapping) and fall back to str(annotation) for constructs without __name__.
…s light The memory package eagerly star-imported its torch/tiktoken/openai-backed modules, so ANY import of the package — including the config loader importing a memory submodule while parsing agent configs — dragged torch into processes that never embed anything. In agent venvs that see a NumPy-1.x-built torch next to a venv numpy 2.x, that import also spews the "compiled using NumPy 1.x cannot be run in NumPy 2.4.6" warning wall on every boot. PEP 562 module __getattr__ defers each optional module until its class is actually accessed; a missing optional dependency surfaces as the same AttributeError shape as the old guarded imports. Verified: importing the package or any plain submodule no longer pulls torch; token_chunker, vector_memory, and tools suites pass (20/20).
Tool schemas carried raw Python type names — Optional, Union, dict,
list, float — which lenient providers tolerated but OpenAI strictly
validates: a single Optional[list[str]] parameter 400s the entire
request ("Invalid schema for function ... 'Optional' is not valid").
_annotation_type_name now resolves real typing objects via
get_origin/get_args (Optional[list[str]] → array on every Python
version, instead of leaking the version-dependent __name__), maps
plain classes and string annotations through a JSON Schema vocabulary
table, and degrades unknowns to string — never to an invalid schema.
pnpm 10 stopped reading the "pnpm" field in package.json (overrides, onlyBuiltDependencies), so the frozen install in CI fails with ERR_PNPM_LOCKFILE_CONFIG_MISMATCH ever since the unpinned setup action started installing pnpm 10+. Move the settings to pnpm-workspace.yaml (allowBuilds replaces onlyBuiltDependencies — only esbuild may run install scripts, matching the previous policy), regenerate the lockfile, and pin packageManager so the toolchain stops drifting under CI.
treo
approved these changes
Jun 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Four robustness fixes in the tool provider, LLM client, and memory package, plus a CI repair:
1.
list_toolsno longer crashes on string annotations (5409ffe) —param.annotation.__name__raisedAttributeErrorfor modules usingfrom __future__ import annotations; one such tool broke every interaction with the agent.2. Tool schemas only emit valid JSON Schema types (
17f6a9a) — parameter types carried raw Python names (Optional,dict,list,float); strict providers (OpenAI) reject the entire request over a single invalid type. Real typing objects resolve viaget_origin/get_args(version-independent), string annotations map through a vocabulary table, unknowns degrade tostring.3. Tool-call arguments parse tolerantly (
791b444) — models routinely emit raw control characters (literal newlines) inside JSON string values of tool-call arguments; strictjson.loadsrejected those and one malformed tool call aborted the entire turn.strict=False, with a{"_raw": ...}degradation for anything still unparseable, so the tool reports a bad argument instead of the run dying.4. The memory package no longer imports torch eagerly (
aa5bca6) — PEP 562 lazy loading for the torch/tiktoken/openai-backed embedders; config loading stops paying the torch import (and NumPy ABI warnings) in processes that never embed.CI (
0ab0005): pnpm ≥ 10 stopped reading thepnpmfield inpackage.json; settings moved topnpm-workspace.yamlandpackageManagerpinned. Pipeline is green.Tests: tools 10/10, new llm argument-parsing suite 5/5, all on Python 3.11.