Runs one turn of a voice agent's engine against a conversation you supply and streams the reply as server-sent events. Nothing is stored and no call is created. This is what the dashboard's Test LLM panel uses. You keep the conversation state on your side: send the full message history and the current_node_id or current_state from the previous done event.
The member role may call this route.
Request#
Path parameters#
| Parameter | Type | Required | Description |
|---|---|---|---|
agent_id |
string | Yes | The voice agent to test. |
Body#
| Field | Type | Required | Description |
|---|---|---|---|
messages |
object[] | No | Conversation so far: { "role", "content" } with role user, agent, assistant or system. Default [] (the agent's greeting, if any). |
dynamic_variables |
object | No | Values for {{variables}}. Default {}. |
current_node_id |
string | No | Conversation flow: node the conversation is on. |
current_state |
string | No | Multi-prompt LLM: state the conversation is in. |
agent_version |
integer | No | Version to test. Default: the latest version. |
tool_mocks |
object[] | No | Up to 50 { "tool_name", "output" }. A matching tool call gets this output instead of running, and the agent continues. |
start_component_id |
string | No | Conversation flow only: start at this component's Begin node; reaching its Exit node ends the conversation. |
Example request#
curl -N -X POST "https://api.tried.com.au/agent-playground-completion/agent_3f9a1c0b2d4e5f6a7b8c9d0e" \
-H "Authorization: Bearer $TRIED_API_KEY" \
-H "Content-Type: application/json" \
-d '{"messages":[{"role":"user","content":"What are your hours?"}],"dynamic_variables":{"customer_name":"Sam"}}'const res = await fetch("https://api.tried.com.au/agent-playground-completion/agent_3f9a1c0b2d4e5f6a7b8c9d0e", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.TRIED_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ messages: [{ role: "user", content: "What are your hours?" }] }),
});
const text = await res.text();
const events = text.split("\n\n").filter(Boolean).map((block) => JSON.parse(block.replace(/^data: /, "")));import json, os, requests
res = requests.post(
"https://api.tried.com.au/agent-playground-completion/agent_3f9a1c0b2d4e5f6a7b8c9d0e",
headers={"Authorization": f"Bearer {os.environ['TRIED_API_KEY']}"},
json={"messages": [{"role": "user", "content": "What are your hours?"}]},
stream=True,
)
for line in res.iter_lines(decode_unicode=True):
if line.startswith("data: "):
print(json.loads(line[6:]))Response#
200 OK with Content-Type: text/event-stream. Each event is one data: <json> line followed by a blank line.
data: {"type":"delta","content":"We're "}
data: {"type":"delta","content":"open 9 to 5."}
data: {"type":"done","content":"We're open 9 to 5.","current_node_id":null,"current_state":null}type |
Fields | Meaning |
|---|---|---|
delta |
content |
Next piece of the reply text. |
tool_call |
tool_call_id, name, arguments |
The agent called a tool. |
tool_result |
tool_call_id, name, content, mocked: true |
Output from a matching tool_mocks entry. |
node_transition |
former_node_id, new_node_id |
The flow moved to another node. |
end |
node_id, reason |
The conversation reached an end node (end_node) or the Exit of the component under test (component_exit). |
done |
content, current_node_id, current_state |
The full reply and the position to send back next turn. |
error |
message |
The turn failed. The stream then closes. |
Without an LLM key for the agent's model, a mock reply is streamed. Needs keys
Errors#
| Status | When |
|---|---|
400 |
Validation failed. Errors after the stream opens arrive as an error event instead, including a start_component_id on an agent that is not a conversation flow or a component that does not exist. |
401 |
Missing or invalid API key. |
403 |
The key's IP allowlist or scopes reject the request. This route needs the agents scope. |
404 |
The agent or version does not exist. |
429 |
Rate limit exceeded. See Rate limits. |
See Errors for the body format.