Lab: add a tool
From argument schema, execution, and output schema to scoped registration, presentation, and tests
defineTool → ctx.tools.register → prompt schemaBeyond name, description, and execute, what makes a production-grade tool definition?
A tool definition is a quality-controlled product contract: input spec, output spec, deadline, presentation, and error classes must match the production line.
Mechanism
defineTool ties TypeScript inference, JSON Schema compilation, runtime validation, output validation, and presentation to one definition. Unsupported schema keywords are rejected.
Register on agent.ctx for local capability or root ctx for deployment capability. schemas() projects only currently visible tools, while execution still uses the full pipeline.
Define contract
Arguments, output, and errors remain JSON-representable.
What extensions must preserve
- Arguments and output are runtime-validated
- Tool meta must be JSON-serializable
- Tool business logic does not own cross-tool security policy
The tempting wrong turns
- ×Writing TypeScript types without runtime schemas
- ×Returning classes, Date, or cycles from handlers
- ×Registering without lifecycle ownership of the disposer
h25-build-tool.ts TypeScriptexport const apply = (ctx: Context) => {
ctx.tools.register(defineTool({
name: "weather_lookup",
description: "Return a normalized weather snapshot.",
parameters: { city: { type: "string" } },
output: { summary: { type: "string" } },
async execute({ city }, runtime) {
runtime.signal.throwIfAborted()
return { summary: await lookup(city, runtime.signal) }
},
}))
}Do not trust the conclusion—verify it
These anchors are pinned to official deepseek-harness@47f9438; account for later breaking changes when reading current upstream.
Pause for ten seconds before revealing
Why does tool output need a schema?
A tool is a capability consumer. Next we design a replaceable provider and the full seam from the other side.