createPiTools declares every tool's parameters as PiJSONSchema:
interface PiJSONSchema {
type: "object";
properties?: Record<string, unknown>;
required?: string[];
[key: string]: unknown;
}
pi-durable 1.0 types a tool's execute(args) as Static<TParameters>, inferred from parameters. With PiJSONSchema that comes out as {}, so every Workspace tool registered on pi gets untyped arguments. The schema is fine at runtime (pi validates plain JSON Schema with TypeBox); only the static type is lost.
Seen in the agents pi harness example, examples/next/harnesses/pi/src/workspace.ts on cloudflare/agents#2451:
draft.set(tool.name, {
parameters: tool.parameters, // PiJSONSchema
async execute(args) { … } // args: {}
});
Options:
- Declare each tool's schema as its exact literal type (
satisfies, not widened to PiJSONSchema), and type tools as a tuple or a record keyed by name so each tool keeps its own schema type.
- Build the pi-ai schemas with TypeBox (
Type from @earendil-works/pi-ai, or typebox as an optional peer). Static then infers the args.
- Also export a per-tool
execute(args, context) for each declaration, so a pi-durable host doesn't have to route by name through the single execute(call).
createPiToolsdeclares every tool'sparametersasPiJSONSchema:pi-durable 1.0 types a tool's
execute(args)asStatic<TParameters>, inferred fromparameters. WithPiJSONSchemathat comes out as{}, so every Workspace tool registered on pi gets untyped arguments. The schema is fine at runtime (pi validates plain JSON Schema with TypeBox); only the static type is lost.Seen in the agents pi harness example,
examples/next/harnesses/pi/src/workspace.tson cloudflare/agents#2451:Options:
satisfies, not widened toPiJSONSchema), and typetoolsas a tuple or a record keyed by name so each tool keeps its own schema type.Typefrom@earendil-works/pi-ai, ortypeboxas an optional peer).Staticthen infers the args.execute(args, context)for each declaration, so a pi-durable host doesn't have to route by name through the singleexecute(call).