Choose a recipe by the behavior you need
Recipes are small composition patterns, not interchangeable complete files. Start from a working version: "2" config such as the first tool, then merge the relevant section. A block beginning with - id: is a tool entry; a block beginning with request: or behavior: is a fragment inside an existing tool.
Before copying a fragment, declare every input path it reads, every dependency it names, and every target tool it navigates to. The booking walkthrough is the complete alternative when you want a file that runs without assembly.
Understand the result before copying the pattern
A public GET has no user credential and should only expose public data. A session-authenticated GET forwards the user's token and relies on the API's authorization. A service key represents the server, so choose it only when the endpoint's privilege model matches that authority.
Adding confirmation changes a write from immediate execution to needs_confirmation. Adding a private option ID changes what the client sees, but not which internal API value is mapped. Adding a custom store or limiter changes where state is held; it must still satisfy the runtime contract.
Check a composed recipe
Compile the merged config, then invoke it with a mock response and assert the outgoing HTTP. Test the absent value and rejection path too. Do not copy a confirmation preview containing $.service_name unless service_name is declared and populated. Do not add recovery for availability unless that dependency is declared on the same tool.
The host snippets below assume existing authorized session/message/token values and your own render functions. They are wiring examples; status-aware rendering from runtime flow is still required.
This page is meant to be copied from.
Public read-only GET
- id: list-categories
tool:
description: List public categories.
input_schema:
type: object
properties: {}
request:
method: GET
url: https://api.example.com/categories
User-authenticated GET
- id: my-bookings
tool:
description: List the signed-in user's bookings.
input_schema:
type: object
properties: {}
request:
method: GET
url: https://api.example.com/bookings
auth:
type: session
Host:
runtime.chat({
sessionId,
message: "Show my bookings",
auth: { token: accessToken },
});
Service API key
request:
auth:
type: api-key
env: PARTNER_API_KEY
header: X-API-Key
POST with confirmation
behavior:
effect: side-effect
confirmation:
required: true
preview:
service: $.service_name
date: $.date
request:
method: POST
url: https://api.example.com/bookings
Destructive action
behavior:
effect: destructive
confirmation:
required: true
Use a clear preview and a host UI that visibly distinguishes destructive intent.
Direct invoke without a model
const runtime = await AgentRuntime.create({
configPath: "./config.yml",
presentation: "raw",
});
await runtime.invoke({
sessionId,
tool: "list-categories",
arguments: {},
});
AI conversation + raw authoritative UI
const result = await runtime.chat({
sessionId,
message,
presentation: "both",
});
renderNaturalLanguage(result.message);
renderStructuredCards(result.data);
Trusted tenant context
await runtime.chat({
sessionId,
message,
context: {
tenant: { id: tenantId },
},
});
request:
map:
headers:
X-Tenant-Id:
source: session
path: $.tenant.id
Abort a request
const controller = new AbortController();
const promise = runtime.chat({
sessionId,
message,
signal: controller.signal,
});
controller.abort();
Sensitive selection ID
selection:
items_path: $.accounts
id_path: $.internal_id
label_path: $.display_name
id_sensitive: true
Stale availability recovery
behavior:
effect: side-effect
confirmation:
required: true
recovery:
refresh_dependency: availability
statuses: [409, 410]
Use when a confirmed write can legitimately become stale between selection and execution. The runtime refreshes the read-only dependency and asks the user again rather than silently reissuing the write.
Custom rate limiter
const runtime = await AgentRuntime.create({
configPath: "./config.yml",
rateLimiter: sharedLimiter,
});
Implement:
interface RateLimiter {
consume(key: string, limit: number, windowMs: number): Promise<void>;
}
Custom retriever for thousands of tools
const runtime = await AgentRuntime.create({
configPath: "./config.yml",
retriever: myVectorOrDomainRetriever,
});
Return only valid tool IDs and scores; the ToolRouter still validates candidates and final tool calls.