Agent Development Kit · Start
Ask a booking agent. Watch it use a tool.
A live model reads your request, decides whether to look up a booking, and answers with the result. Your tool updates typed application state. Run it, change the question, and inspect the state and tool calls it produced.
Connect your model.
Save an OpenAI API key, then run the cells in order or press Run all. Requests go directly
from this browser to api.openai.com and incur provider usage. The key stays in
this browser's localStorage until you clear it. The booking data is fictional; the model calls
are live.
Explore the runtime without a key using the separate scripted test example.
Step 1
Define what the application remembers.
One schema types every ctx.state read and write. The tool looks up a booking and
records its reference and slot. Building these definitions does not call a model.
import { adk } from '@animahealth/adk'
import { z } from 'zod'
const app = adk({
schema: {
session: {
reference: z.string().default(''),
slot: z.string().nullable().default(null),
},
},
})
const bookings: Record<string, string> = {
'B-42': 'Tuesday at 14:30',
'B-73': 'Friday at 09:00',
}
const lookupBooking = app.tool({
name: 'lookup_booking',
description: 'Look up an appointment by its booking reference.',
schema: z.object({ reference: z.string() }),
execute: (ctx) => {
ctx.state.reference = ctx.args.reference
ctx.state.slot = bookings[ctx.args.reference] ?? null
return { reference: ctx.state.reference, slot: ctx.state.slot }
},
})
lookupBooking.name
Step 2
Choose what the model sees.
The agent gets instructions, the last lookup from typed state, and conversation history. Context is rebuilt before each model call, so the next call sees state written by the tool.
import { openai } from '@animahealth/adk/openai'
const assistant = app.agent({
name: 'booking-assistant',
model: openai('gpt-5.6-luna'),
context: [
app.context.system(({ state }) =>
'Help with booking questions. Look up references before giving appointment times. ' +
'If the reference is missing, ask for it. A null slot means no booking was found. ' +
`Last lookup: ${state.reference || 'none'}. Slot: ${state.slot ?? 'none'}.`,
),
app.context.history(),
],
tools: [lookupBooking],
})
assistant.name
Step 3
Let the model decide what to do.
Run this cell to make a live request. The agent should call lookup_booking
for B-42 and answer with Tuesday at 14:30. Its wording can vary. Nothing in the script
supplies a model response or tells the runner which tool to call.
const question = 'What time is booking B-42?'
const run = await app.run(assistant, {
input: { message: question, initialState: { session: {} } },
})
run.output.text
Change B-42 to B-73 for a different appointment. Try B-99 for a missing booking, or “When is my appointment?” to see whether the agent asks for a reference. Each run starts a new session, so you can compare the choices without earlier conversation influencing them.
Step 4
Read the state and the tool events.
For B-42, expect reference: "B-42" and slot: "Tuesday at 14:30".
Those values come from your tool. The session events show which arguments the model chose and
what the tool returned. A request that needs clarification may finish without a tool call.
const outcome = {
status: run.status,
state: { reference: run.state.reference, slot: run.state.slot },
tools: run.session.events.filter((event) =>
event.type === 'tool_call' || event.type === 'tool_result',
),
usage: run.usage,
}
outcome
You have a live agent, structured application state, and explicit model context. The Context guide shows how to select and filter history when several agents work in one session.
Keep building.
- Install and setup to run ADK in your own project.
- Add approval and resume with the Bookings sample.
- Compose several agents with steps, sequences, and parallel branches.
- Test a workflow without model calls, or evaluate live model behavior.
- Use tools and state in a voice agent.