Creating an agent
Agents are defined in a folder and synced using the CLI (or SDKs).
Text agent
The structure of the agent folder looks like this:
agents/support/
agent.yaml
instructions.md
guardrail.md
knowledge/returns.md
skills/refund.mdThe CLI makes it easy to create an agent folder:
curl -fsSL https://getstream.io/cli/beta/install.sh | bash # the agents commands are in the beta CLI
getstream agents init my-agent --template text # or --template voiceagent.yaml sets up the agent's model selection, connectors, tool calling, MCP and so on.
name: support
mode: text
# the model to use, can reference a router or a model
llm: llm-fast
# connectors & MCP
connectors:
- name: github
connection: company # one GitHub account your app owns
tools: [list_issues, get_*]
# if you need code execution
sandbox: daytonaconnection: company is one GitHub account your app owns, so nobody signs in. Create it as in App connection. See User connection to let each user connect their own. tools limits which tools it offers; leave it out for all of them. To add any other MCP server, see Custom MCP servers.
connectors is read by the CLI (beta).
llm can name a route from your LLM router or a provider/model.
instructions.md tells the agent what to do:
You are Acme's support agent. Look up policies in your knowledge base before
answering. If someone asks for a refund, use the refund skill.Try your agent using the CLI:
getstream agents test support --syncguardrail.md aims to prevent your agent from answering questions it shouldn't.
You don't want your support bot answering "Why is the sky blue?" or "Solve Navier-Stokes".
It runs a decision model in parallel to the LLM response. Keep in mind that these tools never capture 100% of abuse.
See Guardrails for blocking mode, thresholds and webhooks:
---
refusal: I can only help with questions about your Acme account and orders.
---
Answer questions about Acme products, orders, billing, shipping and returns.
Refuse anything else.knowledge/ contains markdown files and URLs which are indexed. knowledge/urls.yaml allows you to index URLs. See Knowledge and skills.
For more advanced use cases you can expand on this with tool calling.
Items can be returned within 30 days of delivery for a full refund to the
original payment method. After 30 days, Acme offers store credit instead.
Opened headphones can only be returned if they are faulty.skills/ make it easy to define a process for an agent.
You could have a "refund" skill, or "package_tracking" or basically anything.
Skills are the most important part of building a useful agent.
See Skills for every option:
---
description: work out whether a customer is owed a refund, and how much
---
Read the return policy and the order details the customer gave. Say whether
they are owed a refund, how much, and to which payment method. Two sentences
at most. If you need something only the customer knows, ask for it.Sync your agent and talk to it:
getstream agents test support --syncAnd for example ask: "What is your return policy?" to see the knowledge base answer, then "I bought headphones 40 days ago, can I get my money back?" to see the agent load the refund skill and follow it.
Voice agent
The approach for voice AI is just as straightforward. You can create a voice agent from the CLI like this:
getstream agents init my-agent --template voiceAlternatively you can edit the agent.yaml for the agent you already have. The changes you want to make are:
- Subagent: the fast conversational model hands off harder questions to the subagent, as in OpenAI's voice agents. So you typically want a fast conversational model and a slower, thinking subagent.
- stt/tts: a specific model or a router
- greeting: how the agent says hello (fixed text, or varied each time)
- keyterms: optional terms common to your use case
name: support
mode: voice # joins a call
llm: llm-fast
subagent: llm-thinking
stt: en-low-latency # transcription
tts: en-low-latency # the voice it speaks with
greeting:
text: Northwind Pizza, what can I get you?
mode: variation # don't always say the exact same thing
keyterms: [Acme, store credit]getstream agents test support --syncTo run on a native speech-to-speech model instead, name an sts route. It replaces stt, tts and llm:
name: support
mode: voice
sts: en-low-latency
subagent: llm-thinkingOther channels
The same agent can answer on other channels too:
Give it a number, or bring your own SIP trunk.
Answer on WhatsApp with your own Meta app.
Answer over iMessage on your own Linq line.
Answer over SMS on your own Telnyx number.
Answer in Slack threads as your workspace's bot.
See Connectors for everything else it can reach. To let it see, see Video.
Agent deep dive
To recap:
| Path | What it holds | Learn more |
|---|---|---|
agent.yaml |
What the agent runs on | agent.yaml |
instructions.md |
The system prompt | |
guardrail.md |
What it will and will not answer | Guardrails |
skills/*.md |
Workflows loaded when they are needed | Knowledge and skills |
knowledge/*.md |
What it may look things up in | Knowledge and skills |
knowledge/urls.yaml |
Pages the backend crawls into the knowledge base | Adding URLs to knowledge |
simulations/*.yaml |
Conversations to test it with | Simulations and evals |
.agent_sync |
Written by the sync: what was last synced, and when |
Only agent.yaml is required
agent.yaml
Every key names a route or setting rather than hard-coding a model:
| Key | What it sets |
|---|---|
name |
The config's name, which sessions are opened by. The CLI requires it; the SDKs fall back to the directory name. |
description |
A note for whoever reads the config. |
mode |
voice or text. A text agent needs no call and uses no speech routes. Defaults to voice. |
llm |
The route or provider/model that holds the conversation. See LLM. |
subagent |
Voice only: the route skills run on. When agent.yaml names none, the router defaults to llm-thinking when the deployment can route it, and the fast model answers everything itself when it cannot. A text agent runs its skills on its llm and is refused one. See Harness and sandbox. |
stt, tts |
Transcription and voice routes for a cascade (transcribe, answer, speak). See STT and TTS. |
sts |
A native speech-to-speech route. Naming one replaces stt, tts and llm. |
voice |
The voice the agent speaks in, including a cloned one. See TTS. |
greeting |
Said on joining without asking the model. Empty waits to be spoken to. |
search |
The web search route the agent may use. search-fast (Exa, Tavily or Perplexity) when you set none. |
keyterms |
Words the transcriber should expect: names, products, jargon. |
harness |
Which harness runs the agent. default is the only one. |
sandbox |
daytona lets the agent run code: the subagent on a voice agent, the agent itself on a text agent. See Harness and sandbox. |
connectors |
Connectors, including your own for any MCP server. See Tools for the keys. |
video |
source and max_frames (1 to 8) for an agent that looks at video. See Video. |
tags |
Cost labels, so spend can be attributed to whatever they mean to you. |
app |
Your application's own settings. Never sent to Stream, and the one place an unknown key is allowed. |
Going further
To learn more about each feature:
Screen every turn with guardrail.md, a classifier or your own webhook.
Knowledge files, URLs to crawl, and skills.
Test the agent with simulated conversations and a judge.
Hand-off to the subagent, compaction, and running code in a sandbox.
Your own functions, run in your process.
What a connector is, a quickstart, and whose account it uses.