Skip to content

feat(core,vendo): a tool you write by hand is a zod schema and a function - #1464

Merged
yousefh409 merged 2 commits into
mainfrom
yousefh409/ingest-s1-definetool
Aug 18, 2026
Merged

feat(core,vendo): a tool you write by hand is a zod schema and a function#1464
yousefh409 merged 2 commits into
mainfrom
yousefh409/ingest-s1-definetool

Conversation

@yousefh409

@yousefh409 yousefh409 commented Aug 18, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds defineTool — a typed helper for authoring host tools by hand. Today the tools: slot already accepts a ToolDefinition, but writing one meant hand-authoring JSON Schema beside the TypeScript execute function and keeping the two honest about each other forever, with nothing checking they agreed.

defineTool takes the input schema once, as zod, and derives both halves: the JSON Schema the model is shown, and the runtime parse that validates arguments before execute runs. 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 / vendoai umbrella:

export function defineTool<Input extends z.ZodType>(tool: {
  name: string; description: string; input: Input;
  risk: GradedRiskLabel;
  execute(input: z.infer<Input>, context: RunContext): Promise<Json>;
}): ToolDefinition;

risk is required and graded — ungraded stays extraction's own answer. The return is a plain ToolDefinition (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 defineTool itself (schema-to-JSON-Schema derivation, argument validation, risk requirement) plus 3 seam tests that exercise a defineTool-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 defineTool to build host tools from a Zod v4 schema and an execute function. 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.

  • Public API and exports: defineTool({ name, description, input, risk, execute }) returns a plain ToolDefinition you can spread; the derived inputSchema omits $schema. Exported from @vendoai/core and @vendoai/vendo. Adds a “Custom tools” docs page.
  • Validation behavior: uses async parsing so Zod refinements that await do not throw; invalid inputs never reach execute.
  • Risk and migration: risk is required and graded; ungraded remains extraction-only. Zod 4 shapes only — on Zod 3.25+ import z from zod/v4; otherwise upgrade to Zod 4.

Written for commit 7d48075. Summary will update on new commits.

Review in cubic

…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>
@mintlify

mintlify Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
Vendo 🟢 Ready View Preview Aug 18, 2026, 12:26 PM

@greptile-apps

greptile-apps Bot commented Aug 18, 2026

Copy link
Copy Markdown

Greptile Summary

Adds 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 defineTool; asynchronous parsing now completes and reports validation failures normally.

Confidence Score: 4/5

One non-security P1 failure remains: call-aware custom tools created through defineTool cannot receive their ToolCall metadata.

The actionable findings contain exactly one non-security P1, which maps to confidence 4.

Files Needing Attention: packages/core/src/define-tool.ts

T-Rex T-Rex Logs

What T-Rex did

  • T-Rex produced a proof for a posted P1 finding, validating the finding with a formal proof.

T-Rex Ran code and verified through T-Rex

Reviews (2): Last reviewed commit: "fix(core): defineTool parses async schem..." | Re-trigger Greptile

Comment thread packages/core/src/define-tool.ts Outdated
Comment thread packages/core/src/define-tool.ts
… 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>
Comment thread packages/core/src/define-tool.ts
@yousefh409
yousefh409 added this pull request to the merge queue Aug 18, 2026
Merged via the queue into main with commit df0b4cb Aug 18, 2026
25 checks passed
@yousefh409
yousefh409 deleted the yousefh409/ingest-s1-definetool branch August 18, 2026 20:48
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.

1 participant