Middleware
Add named instructions, tools, model selection, context, policy, and session-local state.
Middleware runs around each model step. Use capabilities for the common declarative case and a
StepMiddleware when the behavior must inspect a step, change its configuration, review a
candidate, or request an interaction.
const policy = {
id: "policy",
instructions: ["Never expose account data without approval."],
middleware: async (request, next) => {
const response = await next();
for (const call of response.toolCalls()) {
if (call.name === "delete_account") {
response.requireInteraction(call.id, {
kind: "approval",
prompt: "Approve account deletion?",
});
}
}
return response;
},
};What middleware can contribute
- Instructions and tools: use named slots to supply model-visible values.
- Model selection: set, replace, or clear a
ModelDirectivefor a step. - Runtime context: add JSON context items without folding them into the configuration policy.
- Candidate policy: replace a candidate, deny a tool call, require interaction, or raise a tripwire.
- Session-local state: declare
state.create()and receive the state asynchronously in that capability's handler and tools.
Harness records contributors, ordering, and digests for model configuration and context. It also
enforces the middleware contract: call next() at most once and make request mutations before the
middleware returns.
Tools are host services
Tools are typed Zod object schemas plus an async executor. Return a completed, denied, failed, interaction-required, or deferred outcome. The tool executor receives IDs, an abort signal, and—if applicable—the answer to a required interaction.
Construct service clients outside the tool and make application authorization decisions in the executor or middleware. Harness validates arguments and schedules eligible calls; it never supplies your service credentials or performs external authorization.
Read the exact shapes in Tools and Middleware.