feat(core,vendo): a tool you write by hand is a zod schema and a function - #1464
Conversation
…tion The `tools:` slot already took a `ToolDefinition`, but authoring one meant writing JSON Schema by hand beside the TypeScript function and keeping the two honest about each other forever — nothing checked they agreed. `defineTool` takes the schema once, as zod, and derives both halves: the JSON Schema the model is shown, and the parse that runs before `execute`. Arguments the schema rejects are refused naming the field, and the body never runs. `risk` is required and graded; `ungraded` stays extraction's answer alone. What comes back is a plain `ToolDefinition`, so every field the helper does not ask for is still a spread away. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Preview deployment for your docs. Learn more about Mintlify Previews.
|
Greptile SummaryAdds a public Zod-backed helper for custom tool definitions, including schema projection, argument validation, exports, documentation, and coverage. One existing integration defect remains: custom tool handlers do not receive the call metadata supplied by the execution contract. The earlier asynchronous-schema concern was disproved by executing valid and invalid asynchronous Zod refinements through Confidence Score: 4/5One non-security P1 failure remains: call-aware custom tools created through The actionable findings contain exactly one non-security P1, which maps to confidence 4. Files Needing Attention: packages/core/src/define-tool.ts
What T-Rex did
Reviews (2): Last reviewed commit: "fix(core): defineTool parses async schem..." | Re-trigger Greptile |
… the parse A zod schema whose refinement awaits anything throws $ZodAsyncError out of the synchronous safeParse, before the validation error can be produced. The wrapper is already async, so safeParseAsync costs a sync schema nothing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Summary
Adds
defineTool— a typed helper for authoring host tools by hand. Today thetools:slot already accepts aToolDefinition, but writing one meant hand-authoring JSON Schema beside the TypeScriptexecutefunction and keeping the two honest about each other forever, with nothing checking they agreed.defineTooltakes the input schema once, as zod, and derives both halves: the JSON Schema the model is shown, and the runtime parse that validates arguments beforeexecuteruns. Arguments the schema rejects are refused by naming the field, and the body never executes.Public surface
packages/core/src/define-tool.ts, value-exported from the@vendoai/vendo/vendoaiumbrella:riskis required and graded —ungradedstays extraction's own answer. The return is a plainToolDefinition(generic erased), so any field the helper doesn't ask for is still a spread away (e.g.{ ...defineTool({...}), confirmEach: true }).Testing
4 unit tests on
defineToolitself (schema-to-JSON-Schema derivation, argument validation, risk requirement) plus 3 seam tests that exercise adefineTool-built tool through the real guard — no stub on either side.Stack
Part of a 4-PR stack (data ingestion + custom tools + connectors + tenant connectors). This PR is the bottom of the stack; the next PR (
openApiConnector) is based on this branch. The merge unit is the stack tip — this PR is a review window, not an independent merge.🤖 Generated with Claude Code
Summary by cubic
Defines
defineToolto build host tools from a Zod v4 schema and anexecutefunction. Previously you hand‑authored JSON Schema beside the function; now we derive the model-facing schema and validate inputs (including async refinements) before execution, rejecting invalid calls by field.defineTool({ name, description, input, risk, execute })returns a plainToolDefinitionyou can spread; the derivedinputSchemaomits$schema. Exported from@vendoai/coreand@vendoai/vendo. Adds a “Custom tools” docs page.awaitdo not throw; invalid inputs never reachexecute.riskis required and graded;ungradedremains extraction-only. Zod 4 shapes only — on Zod 3.25+ importzfromzod/v4; otherwise upgrade to Zod 4.Written for commit 7d48075. Summary will update on new commits.