This release includes 1 breaking change for platform teams planning a safe upgrade.
✓ No known CVEs patched in this version
Topics
+10 more
ReleasePort's take
Light signalMCP tool parameters now strictly validate enums, unions, and nested models; LLM retry logic fails fast on non‑retryable 4xx errors instead of using exponential backoff.
Why it matters: Strict validation of MCP tool parameters eliminates misconfiguration risks; failing fast on unretryable 4xx LLM responses prevents unnecessary latency and resource waste.
Summary
AI summaryUpdates https://github.com/alexagr, retryable, and https://github.com/langroid/langroid/pull/1055 across a mixed release.
Changes in this release
| Type | Severity | Summary | CVE |
|---|---|---|---|
| Breaking | High |
MCP tool parameters now strictly validate enums, unions, and nested models. MCP tool parameters now strictly validate enums, unions, and nested models. Source: llm_adapter@2026-07-13 Confidence: high |
— |
| Bugfix | Medium |
Fail fast on non‑retryable 4xx LLM errors instead of retrying with exponential backoff. Fail fast on non‑retryable 4xx LLM errors instead of retrying with exponential backoff. Source: llm_adapter@2026-07-13 Confidence: high |
— |
Full changelog
0.65.9 — Precise MCP tool-parameter types, and fail-fast on non-retryable LLM errors
Two improvements this release, both originally contributed by
@alexagr: MCP tool parameters now map to precise
Python types — so they validate correctly and the LLM sees accurate schemas —
and the LLM retry logic now fails fast on non-retryable 4xx errors instead of
retrying them with exponential backoff.
pip install -U langroid
Precise MCP tool-parameter types (#1059)
When Langroid builds a ToolMessage from an MCP tool,
FastMCPClient._schema_to_field converts each parameter's JSON Schema into a
Python type. Several common constructs were previously dropped — falling
through to a plain scalar or to Any — so the generated tool lost type
information both for validation and in the schema the LLM sees. They now map to
precise types:
enum/const→typing.Literal.anyOf/oneOf→typing.Union; a{"type": "null"}branch (or an
optional parameter) makes itOptional— the commonOptional[...]shape
fastmcp emits.allOfwith a single subschema → that subschema; a multi-schema intersection
falls back toAny.$refinto the tool's$defs(pydantic-model params, including inside unions
and array items) → a nested pydantic model, with reference cycles degrading
the cyclic edge toAny.
This release also fixes a Pydantic v1→v2 regression in
ToolMessage.llm_function_schema(): the nested-model schema cleanup keyed off
v1's "definitions", but v2 emits "$defs", so under Langroid's v2 the cleanup
silently no-op'd — leaking purpose / id / exclude and an unconstrained
request into nested ToolMessage schemas sent to the LLM. It now tracks the
v2 key.
Why it matters:
- Validation — out-of-set
enumvalues and wrong-type union values now
raiseValidationErrorinstead of being silently accepted. - Better LLM grounding — pydantic re-emits
enum,anyOf, and nullability
in the schema, so the model receives exact parameter types instead of
"string"/"any".
Behavior change: MCP tools with enum / union / nested-model params are now
strictly validated; a value that violates a (previously dropped) constraint now
raises ValidationError. Well-formed calls are unaffected.
Fail fast on non-retryable 4xx LLM errors (#1058)
The retry decorators (retry_with_exponential_backoff and its async variant)
decided non-retryability by substring-matching str(e). But a native
OpenAI-SDK error stringifies to Error code: 404 - ..., which does not
contain the class name, so native 403 / 404 errors — e.g. a retired or
unknown model on an OpenAI-compatible endpoint such as Gemini — slipped past the
guard and were retried with exponential backoff instead of failing immediately.
A type-based guard now catches the non-retryable 4xx errors
(BadRequestError 400, AuthenticationError 401, PermissionDeniedError 403,
NotFoundError 404, UnprocessableEntityError 422) in both the sync and async
paths and raises them immediately. This also closes two latent gaps: the async
path was missing 422 handling and neither path handled 403. Retryable errors
(429, 5xx, timeouts) are unaffected, and the substring guard is retained as a
fallback for LiteLLM-proxy-wrapped errors.
Behavior change: a non-retryable 4xx error now fails fast instead of after
several backoff retries — faster, clearer failures, with no change for
transient (retryable) errors.
Credit
Both improvements were originally contributed by
@alexagr in
#1055 and
#1057; this release ships them
with added hardening, tests, and docs.
Upgrade
pip install -U langroid
Full changelog:
0.65.8...0.65.9
Breaking Changes
- MCP tool parameters with `enum`, `anyOf`, `oneOf`, or nested-model JSON Schema now strictly validate; previously dropped constraints no longer silently accept invalid values.
Weekly OSS security release digest.
The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.
No spam, unsubscribe anytime.
Share this release
Related context
Related tools
Earlier breaking changes
- v0.65.5 Blocks code‑execution, file, and network primitives in creation tools by default.
- v0.65.5 Restricts retrieval tools to read‑only queries; write or admin clauses are rejected by default.
- v0.65.3 Raw user messages containing tools registered with `enable_message(..., use=False, handle=True)` are now dropped instead of executed.
- v0.65.2 Restricts eval'd expression builtins to a curated safe set, breaking code that relied on full Python builtins (e.g., __import__, open).
- v0.65.1 Rejects additional PostgreSQL-specific obfuscations of dangerous functions like `pg_read_file` in `SQLChatAgent`.
Beta — feedback welcome: [email protected]