You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
In packages/agent-runtime, ensureJsonSchemaCompatible(schema: z.ZodType) recovers from non-serializable schemas (such as z.function()) by generating a passthrough fallback object and copying the schema's description:
Under Zod v4, accessing the .description getter on a function schema evaluates schema._zod.parent. Because parent is undefined for function schemas, this throws an unhandled TypeError: undefined is not an object (evaluating 'schema._zod.parent') inside the recovery handler, crashing getToolSet and failing unit tests in prompts-schema-handling.test.ts.
Additionally, under Zod v4, .and() directly merges intersected object schema properties into the top-level properties instead of wrapping them in an allOf construct.
Changes Made
Guarded schema.description access in a nested try / catch block within ensureJsonSchemaCompatible() in both packages/agent-runtime/src/tools/prompts.ts and packages/agent-runtime/src/templates/prompts.ts, ensuring non-serializable schemas return the fallback object cleanly without throwing.
Updated prompts-schema-handling.test.ts to assert that converted MCP parameter properties (name, cb_easp) are preserved.
Architecture & Conventions Conformance
Adheres to Dependency Injection (contracts defined in common/src/types/contracts/, no module monkey patching)
Terminal commands use terminalCommandBroker (no direct spawn or TUI-process bypass)
Environment hygiene respected (getCliEnv() for CLI, getSdkEnv() for SDK, no forbidden getProcessEnv() imports)
Freebuff mode compatibility (IS_FREEBUFF preserved, no paid features introduced)
Imports ordered and explicit (import type used for types)
Scope Verification
All modified files are within allowed public directories: packages/agent-runtime/
NO modifications to web/, freebuff/web/, packages/internal/, packages/billing/, packages/bigquery/, or packages/build-tools/
Testing & Verification
bun test packages/agent-runtime/src/__tests__/prompts-schema-handling.test.ts passed 15/15 tests (was failing 2 tests).
bun run build:sdk passed cleanly.
bun run build:freebuff passed cleanly.
bun cli/scripts/smoke-binary.ts cli/bin/freebuff passed cleanly.
Good diagnosis: schema.description becoming a throwing getter on Zod v4 function schemas inside an already-degraded fallback path is a real bug, and wrapping it in try/catch in both packages/agent-runtime/src/tools/prompts.ts and .../templates/prompts.ts is the right layer to fix it — this is exactly the kind of defensive recovery code that should never itself throw. Small, in-scope, and easy to port.
Two things worth tightening before this lands:
The nested try { ... } catch { return fallback } inside the outer catch works but reads awkwardly. Consider computing the description defensively up front, e.g. let description: string | undefined; try { description = schema.description } catch {}, then return description ? fallback.describe(description) : fallback. Same fix, clearer intent, and it's identical in both files so a small shared helper might be worth it too (duplicated logic across tools/prompts.ts and templates/prompts.ts already existed before this PR, but it's growing).
The test change removes the expect(description).toContain('allOf') assertion and renames the test rather than adding a new test for the actual crash being fixed (calling ensureJsonSchemaCompatible on a z.function() schema with a .describe() on it, which is the actual repro from your bug report). Right now the PR's own regression — the .description getter throwing — isn't directly exercised by any test; the diff only patches an unrelated MCP-params test to match a Zod v4 behavior change in .and(). Please add a test that would fail on the pre-patch code (a described function schema hitting ensureJsonSchemaCompatible) so this doesn't regress silently on the next Zod bump.
Substance is right; needs a direct regression test for the crash itself before it's fully port-ready.
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
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.
Problem & Context
In
packages/agent-runtime,ensureJsonSchemaCompatible(schema: z.ZodType)recovers from non-serializable schemas (such asz.function()) by generating a passthrough fallback object and copying the schema's description:Under Zod v4, accessing the
.descriptiongetter on a function schema evaluatesschema._zod.parent. Becauseparentis undefined for function schemas, this throws an unhandledTypeError: undefined is not an object (evaluating 'schema._zod.parent')inside the recovery handler, crashinggetToolSetand failing unit tests inprompts-schema-handling.test.ts.Additionally, under Zod v4,
.and()directly merges intersected object schema properties into the top-level properties instead of wrapping them in anallOfconstruct.Changes Made
schema.descriptionaccess in a nestedtry / catchblock withinensureJsonSchemaCompatible()in bothpackages/agent-runtime/src/tools/prompts.tsandpackages/agent-runtime/src/templates/prompts.ts, ensuring non-serializable schemas return the fallback object cleanly without throwing.prompts-schema-handling.test.tsto assert that converted MCP parameter properties (name,cb_easp) are preserved.Architecture & Conventions Conformance
common/src/types/contracts/, no module monkey patching)terminalCommandBroker(no directspawnor TUI-process bypass)getCliEnv()for CLI,getSdkEnv()for SDK, no forbiddengetProcessEnv()imports)IS_FREEBUFFpreserved, no paid features introduced)import typeused for types)Scope Verification
packages/agent-runtime/web/,freebuff/web/,packages/internal/,packages/billing/,packages/bigquery/, orpackages/build-tools/Testing & Verification
bun test packages/agent-runtime/src/__tests__/prompts-schema-handling.test.tspassed 15/15 tests (was failing 2 tests).bun run build:sdkpassed cleanly.bun run build:freebuffpassed cleanly.bun cli/scripts/smoke-binary.ts cli/bin/freebuffpassed cleanly.