Actor Configuration Standard
This page is the authoritative specification for the Actor YAML format. Every field, type, constraint, and behavior is documented here.
Top-level structure
name: string # required — unique identifier for this actor
version: string # required — semver string (e.g. "1.0.0")
description: string # optional — human-readable description
agents: # required — list of agent node definitions
- ...
routes: # required — routing configuration
entry: string
...
Top-level fields
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
name | string | yes | Lowercase, alphanumeric + hyphens, 2–64 chars | Actor identifier. Becomes the model ID suffix when deployed. |
version | string | yes | Valid semver | Version of this actor definition. |
description | string | no | Max 500 chars | Human-readable summary of what this actor does. |
agents | list | yes | 1–32 agents | List of agent node definitions. |
routes | object | yes | — | Routing configuration. Must reference agent IDs defined in agents. |
Agent types
Each entry in agents must have a unique id and a type field. The three supported types are llm, router, and tool.
type: llm
An llm agent calls an upstream provider model and optionally applies a system prompt or parameter overrides.
agents:
- id: responder
type: llm
model: openai/gpt-4o-mini # required — model ID (provider/name format)
system_prompt: | # optional — system message text
You are a helpful assistant.
temperature: 0.7 # optional — float 0.0–2.0
max_tokens: 1024 # optional — integer
top_p: 1.0 # optional — float 0.0–1.0
stop: ["\n\n"] # optional — list of stop sequences
passthrough_params: true # optional — forward caller's params (default: true)
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | Unique within this actor |
type | string | yes | Must be "llm" |
model | string | yes | Provider model ID (e.g. openai/gpt-4o) |
system_prompt | string | no | Injected as the system message |
temperature | float | no | Overrides caller's temperature |
max_tokens | integer | no | Overrides caller's max_tokens |
top_p | float | no | Overrides caller's top_p |
stop | list of strings | no | Stop sequences |
passthrough_params | boolean | no | Whether to forward caller's sampling params. Default true. If false, only the actor's configured params apply. |
type: router
A router agent evaluates an expression or runs a quick classification call to determine which agent to invoke next. It does not produce output directly.
agents:
- id: classify
type: router
strategy: llm_classify # "llm_classify" or "expression"
model: openai/gpt-4o-mini # required if strategy is llm_classify
classes: # required — list of class labels
- simple
- complex
prompt: | # prompt used to classify the input
Classify the user's request as "simple" (factual, one-sentence answer)
or "complex" (requires analysis or multi-step reasoning).
Reply with only the class label.
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | Unique within this actor |
type | string | yes | Must be "router" |
strategy | string | yes | "llm_classify" or "expression" |
model | string | yes (if llm_classify) | Model used for classification |
classes | list of strings | yes (if llm_classify) | Valid output class labels |
prompt | string | yes (if llm_classify) | Classification prompt template |
expression | string | yes (if expression) | A Python-safe expression evaluated against request context. Returns a string matching a class label. |
type: tool
A tool agent calls an external HTTP endpoint or a built-in function and injects the result as a message into the conversation before passing to the next agent.
agents:
- id: fetch_docs
type: tool
tool: http # "http" or a registered built-in tool name
url: "https://example.com/api/search"
method: POST # default: GET
body_template: | # Jinja2 template for the request body
{"query": "{{ last_user_message }}"}
headers:
Authorization: "Bearer {{ env.DOCS_API_KEY }}"
inject_as: user # "user" or "system" — how result is injected
result_template: | # Jinja2 template to format the result
Retrieved context:\n{{ response.body }}
| Field | Type | Required | Description |
|---|---|---|---|
id | string | yes | Unique within this actor |
type | string | yes | Must be "tool" |
tool | string | yes | "http" or built-in tool name |
url | string | yes (if http) | Endpoint URL. Supports Jinja2 templating. |
method | string | no | HTTP method. Default GET. |
body_template | string | no | Jinja2 template for the request body. |
headers | map | no | Static or templated HTTP headers. env.VAR reads from server environment. |
inject_as | string | no | "user" or "system". Default "user". |
result_template | string | no | Jinja2 template to format the tool result before injection. |
Route types
The routes block must define an entry agent and one of three routing patterns: stream, graph, or bridge.
stream route
Passes the request directly to the entry agent and streams its output to the caller. This is the simplest pattern — useful for single-agent actors with a custom system prompt.
routes:
entry: responder
stream: true
graph route
Routes the request through a directed graph of agents. Each edge specifies a from agent, a to agent, and an optional condition that must be true (evaluated as a Python expression) for the edge to be followed.
routes:
entry: classify
graph:
- from: classify
to: fast_responder
condition: "classify.output == 'simple'"
- from: classify
to: deep_responder
condition: "classify.output == 'complex'"
- from: fast_responder
to: __end__
- from: deep_responder
to: __end__
__end__ is the reserved terminal node. When execution reaches __end__, the output of the most recent llm agent is streamed to the caller.
| Edge field | Type | Required | Description |
|---|---|---|---|
from | string | yes | Source agent id or __start__ |
to | string | yes | Target agent id or __end__ |
condition | string | no | Python-safe boolean expression. If omitted, edge is unconditional. |
bridge route
Delegates the request to another deployed Actor. Useful for composing complex actors from simpler ones.
routes:
entry: __bridge__
bridge:
actor: my-namespace/another-actor
version: ">=1.2.0" # optional semver constraint
Template context
Jinja2 templates in system_prompt, body_template, result_template, and url have access to:
| Variable | Description |
|---|---|
messages | Full list of messages in the request |
last_user_message | Content of the most recent user message |
env.VAR_NAME | Server environment variable (allowlisted by admin) |
{agent_id}.output | Output text of a completed agent (available in graph conditions) |
Full minimal working example
This example defines a routing Actor that classifies requests as simple or complex and routes to a different model accordingly:
name: smart-router
version: "1.0.0"
description: "Routes simple questions to a fast model, complex ones to a capable model."
agents:
- id: classify
type: router
strategy: llm_classify
model: openai/gpt-4o-mini
classes:
- simple
- complex
prompt: |
Classify the user's request as "simple" (factual, short answer) or
"complex" (requires reasoning, multi-step analysis, or code).
Reply with only the class label.
- id: fast
type: llm
model: openai/gpt-4o-mini
system_prompt: "You give concise, accurate answers."
max_tokens: 256
- id: capable
type: llm
model: openai/gpt-4o
system_prompt: "You give thorough, well-reasoned answers."
max_tokens: 2048
routes:
entry: classify
graph:
- from: classify
to: fast
condition: "classify.output == 'simple'"
- from: classify
to: capable
condition: "classify.output == 'complex'"
- from: fast
to: __end__
- from: capable
to: __end__
Save this as smart-router.yaml, upload it via the Dashboard or CLI, and deploy it to a namespace. It will appear in /v1/models as {namespace}/smart-router.