Skip to content

fix(tools): never crash list_tools on string or exotic annotations#35

Merged
treo merged 4 commits into
mainfrom
fix/tool-provider-string-annotations
Jun 12, 2026
Merged

fix(tools): never crash list_tools on string or exotic annotations#35
treo merged 4 commits into
mainfrom
fix/tool-provider-string-annotations

Conversation

@wmeddie

@wmeddie wmeddie commented Jun 11, 2026

Copy link
Copy Markdown
Member

Four robustness fixes in the tool provider, LLM client, and memory package, plus a CI repair:

1. list_tools no longer crashes on string annotations (5409ffe) — param.annotation.__name__ raised AttributeError for modules using from __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 via get_origin/get_args (version-independent), string annotations map through a vocabulary table, unknowns degrade to string.

3. Tool-call arguments parse tolerantly (791b444) — models routinely emit raw control characters (literal newlines) inside JSON string values of tool-call arguments; strict json.loads rejected 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 the pnpm field in package.json; settings moved to pnpm-workspace.yaml and packageManager pinned. Pipeline is green.

Tests: tools 10/10, new llm argument-parsing suite 5/5, all on Python 3.11.

wmeddie added 4 commits June 11, 2026 11:46
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
treo merged commit cc2b557 into main Jun 12, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants