Tools
Agent tools — defineTool, defineToolchain, Zod validation, parallel execution, and inference message outputs.
Tools extend the processor actor with pluggable capabilities the LLM can invoke. They are agent capabilities inside your product, not APIs you expose to end users.
A coding harness is the usual example: your server owns the workspace. defineTool for read / write / shell lives in the internal package so the agent can work. Users never call those tools — they talk to your session API, which drives Yoke. See Embed Yoke in your product.
Types
type ToolOutput = InferenceMessage | InferenceMessage[];
type Tool = {
name: string;
description: string;
parameters?: z.ZodType;
execute: (input: z.infer<typeof parameters>, ctx: ToolRunContext) => Promise<ToolOutput>;
};
type Toolchain = {
id: string;
description?: string;
tools: Tool[];
};Tool inputs are validated with Zod before execute runs. Outputs must be inference messages — not arbitrary JSON.
Output helpers
import { toolTextMessage, toolInferenceMessage, normalizeToolOutput } from "@yoke/sdk";
// Single text message
await toolTextMessage("Results: ...");
// From message parts
await toolInferenceMessage([{ type: "text", text: "...", format: "plain" }]);
// Normalize to array
normalizeToolOutput(output); // InferenceMessage[]tool_result parts store the inference message array as structured content for the next infer round.
Registration
Static tools
import {
defineAgentStack,
defineTool,
defineToolchain,
toolTextMessage,
z,
} from "@yoke/sdk";
const echoToolchain = defineToolchain("utilities", [
defineTool({
name: "echo",
description: "Echo text back to the model",
parameters: z.object({ text: z.string() }),
execute: async (input) =>
toolTextMessage(JSON.stringify({ echoed: input.text })),
}),
]);
const agentStack = defineAgentStack({
tools: [echoToolchain],
});
defineProcessorActor({
configSchema: processorConfigSchema,
stateSchema: processorStateSchema,
tools: agentStack.tools,
});Lazy resolver
defineAgentStack({
tools: async (ctx) => ({
tools: [],
toolchains: ctx.config.model.startsWith("gpt")
? [searchToolchain]
: [],
}),
});Called when building the provider payload each infer round.
Processor loop
- Resolve tools (static or lazy) → convert Zod to JSON Schema → send to provider
- If response has
tool_callparts:- Post tool calls to monologue (agent author)
- Validate inputs, execute all tools in parallel
- Post
tool_resultparts to monologue (system author) - Run inference again
- Repeat until no tool calls (max 8 rounds)
- Post final
type: "reply"to monologue for egress
Example echo tool
const echoToolchain = defineToolchain("utilities", [
defineTool({
name: "echo",
description: "Echo text back to the model",
parameters: z.object({ text: z.string() }),
execute: async (input) =>
toolTextMessage(JSON.stringify({ echoed: input.text })),
}),
]);Used with createLocalToolLoopProvider and model local-tool-loop for E2E demos without API keys.
Providers
| Provider | Tools support |
|---|---|
createOpenAiProvider | JSON Schema tools |
createAnthropicProvider | JSON Schema tools |
createFixtureProvider | echo tool for tests |
createLocalToolLoopProvider | Local tool loop for demos |
ToolRunContext
execute receives a context with conversation and config access for tools that need to read state or post side-effect messages. Keep tool handlers focused — heavy work should append events for actor processing.