Ingesting is for non-hosted agents: your code runs the agent on your own infrastructure, and you report what happened so AgentOS can show it as runs, events, and reports. AgentOS is the observer — it never executes your agent.
If instead you want AgentOS to run the agent and hand you the output, that's the opposite flow — see Invoking hosted agents.
Every reported run follows the same shape:
startRun() ──▶ run created (status: running)
│
├─ emit(type, payload, level) ×N (progress, tool calls, custom events)
│
└─ complete({ output }) or fail({ error_message }) ──▶ status: completed | failed
You open a run, emit events as work happens, and close it exactly once. The SDK wraps this; the raw endpoints are below.
import { AgentOS } from "@agentos-sdk/core";
const client = new AgentOS({ agentId: "<agentId>", apiKey: "aos_agent_…" });
const run = await client.startRun({ input: { invoiceId: "INV-001" } });
try {
run.emit("invoice.fetched", { rows: 42 });
const result = await processInvoice("INV-001");
await run.complete({ output: { total: result.total } });
} catch (err) {
await run.fail({ error_message: String(err) });
}
Authenticate ingest with an agent key (aos_agent_…). See Authentication.
Every SDK method is a thin wrapper over one ingest endpoint:
| SDK | HTTP endpoint | Purpose |
|---|---|---|
client.startRun() | POST /api/ingest/v1/run/start | Open a run, get a run_id |
run.emit() | POST /api/ingest/v1/events | Append one or more events |
run.complete() | POST /api/ingest/v1/run/complete | Close as completed with output |
run.fail() | POST /api/ingest/v1/run/fail | Close as failed with an error |
run.task() | POST /api/ingest/v1/tasks | Create/update a task |
Full request/response shapes are in the HTTP API reference.
sequence_number so the run timeline renders in the exact order AgentOS received them — emit in the order things happen.occurred_at (ISO 8601) on an event to record when it happened if that differs from when you send it.Pass external_run_id on startRun to store your own identifier (a job id, a message id) alongside the run. It surfaces on the run and lets you map an AgentOS run back to the work item that produced it — handy when reconciling against your own system.
{ "agent_id": "<agentId>", "input": { … }, "external_run_id": "job_8f2a" }
Always close every run — wrap your logic in try/catch and call fail() on error. An unclosed run stays running forever and skews failure-rate and latency metrics.
invoice.fetched, retry.scheduled) — they're just strings and render in the timeline. See Events.See Hosted vs non-hosted for choosing between ingest and invoke, and the HTTP API reference for exact shapes.