Runs
A Run is a single execution of an agent. You start a run, the agent works autonomously using its configured goal and tools, and you get output when it finishes. Every run is logged with a full event timeline for debugging and observability.
Run Lifecycle
| Status | Description |
|---|---|
pending | Queued, waiting to start |
running | Agent is actively executing -- planning, calling tools, reasoning |
completed | Finished successfully, output available |
failed | Something went wrong -- error string available |
cancelled | Cancelled by the user before completion |
Starting a Run
A run is started by specifying the agent ID. The agent uses the goal configured at creation time.
- Python
- JavaScript
from flymyai import AgentClient
client = AgentClient(api_key="fly-***")
run = client.runs.create(agent_id="agent_abc123")
import { AgentClient } from "flymyai-js-client";
const client = new AgentClient({ apiKey: "fly-***" });
const run = await client.runs.create({ agentId: "agent_abc123" });
Run Events
Every run emits ExecutionLog events that provide full visibility into what the agent is doing. Each event has .type, .message, .data, and .created_at.
| Event Type | Description |
|---|---|
declared_functions | Agent declared the functions it plans to use |
tool_called | Agent invoked a tool |
tool_call_exception | A tool call failed with an error |
task_cancelled | The run was cancelled |
Streaming Events
client.runs.stream_events(run_id) yields ExecutionLog objects using polling-based delivery (not SSE).
- Python
- JavaScript
for event in client.runs.stream_events(run.id):
if event.type == "declared_functions":
print(f"Functions: {event.data}")
elif event.type == "tool_called":
print(f"Tool called: {event.message}")
print(f"Details: {event.data}")
elif event.type == "tool_call_exception":
print(f"Tool error: {event.message}")
elif event.type == "task_cancelled":
print("Run was cancelled")
for await (const event of client.runs.streamEvents(run.id)) {
console.log(`[${event.type}] ${event.message || ""}`);
if (event.data) {
console.log(" Data:", event.data);
}
}
Example event stream:
[declared_functions] Declared: tavily_search, browser_navigate
[tool_called] Called tavily_search with query "renewable energy trends 2026"
[tool_called] Called browser_navigate to extract page content
[tool_called] Called tavily_search with query "solar cost decline statistics"
Getting Results
A completed run provides .status, .output, .error, .logs, .messages, and .original_prompt.
- Python
- JavaScript
# Wait synchronously (polls until terminal status)
result = client.runs.wait(run.id, timeout=300, poll_interval=2.0)
print(f"Status: {result.status}")
print(f"Output: {result.output}")
# Or fetch the current state without waiting
result = client.runs.get(run.id)
const result = await client.runs.wait(run.id, { timeout: 300, pollInterval: 2.0 });
console.log(result.output);
Run Detail Fields
| Field | Description |
|---|---|
status | Current run status (see lifecycle above) |
output | The agent's result (alias for agent_result) |
error | Error message string (when status is failed) |
logs | List of ExecutionLog entries |
messages | Conversation messages from the run |
original_prompt | The prompt that was sent to the agent |
Follow-up Messages
You can append a follow-up message to a run:
client.runs.append_message(run.id, text="Can you also check competitor pricing?")
Cancelling a Run
Cancel a run that is still in progress:
client.runs.cancel(run.id)
Listing Runs
# All runs for an agent
runs = client.runs.list(agent_id="agent_abc123")
for run in runs:
print(f"{run.id}: {run.status} ({run.created_at})")
Error Handling
When a run fails, run.error contains a plain error string describing what went wrong.
result = client.runs.get(run.id)
if result.status == "failed":
print(f"Error: {result.error}")
Use stream_events() alongside wait() to get real-time visibility into what the agent is doing. Events of type tool_call_exception can help you diagnose tool-related failures before the run finishes.
Freeze & Re-run
Once a run does what you wanted, you can freeze it. The backend reads the chat, the agent's input_description / output_description, and the schemas, then distills the canonical input → output pipeline into a Markdown instruction. Future executions skip exploration and follow that frozen plan.
# Step 1 - freeze the run (returns once status is "compiled")
compilation = client.agents.compile_from_run(run.id, timeout=120)
print(compilation.instruction_md)
# Step 2a - re-run without variables (agent has no input_schema)
result = client.compilations.run_instruction_and_wait(compilation.id)
# Step 2b - re-run with fresh variables (agent has an input_schema)
result = client.compilations.run_instruction_and_wait(
compilation.id,
variables={"website_url": "https://example.com"},
)
print(result.output) # shaped by output_schema
print(result.output["score"]) # individual fields
What gets dropped: any chat turn outside the input → output path defined by your descriptions and schemas. Exploratory questions, one-off favors, abandoned branches — none of them survive the freeze. See the Python SDK reference for the lower-level building blocks (freeze, run_instruction, wait).