Skip to navigation

Run your first agent

Create a support agent, ask it to summarize a case, and read its result. About ten minutes, with no external tools or model credentials.
View as Markdown

This example uses managed execution and the project default model.

Before you start

  • Python 3.10 or later and uv.
  • A Sikaru project ID.
  • A project API key with managed_agents:write, runs:create, runs:read, and events:read.
  • Agent provisioning and managed execution enabled for your project.

Set up credentials with Authentication.

The commands below make hosted requests and can consume your project’s usage allowance.

Steps

1

Install the Python SDK

Create a project and add the SDK. See SDKs for TypeScript.

uv init sikaru-quickstart
cd sikaru-quickstart
uv add sikaru_api
2

Create the agent

Save this as first_agent.py. The definition holds the agent’s instructions; its digest identifies that exact content. Creation returns the managed agent and its release.

import hashlib
import json
import os
import time
import uuid
from sikaru_api import CreateManagedAgentSourceRequest, SikaruApi
project = os.environ["SIKARU_PROJECT_ID"]
client = SikaruApi(
api_key=os.environ["SIKARU_API_KEY"],
base_url=os.environ["SIKARU_BASE_URL"],
timeout=20,
max_retries=0,
)
agent_slug = "support-quickstart"
definition = {
"schema": "sikaru.agent.contract.v1",
"instructions": (
"Summarize support cases using only the supplied facts. "
"State what is known, what is missing, and the recommended next step. "
"Do not take external actions."
),
"sources": [],
}
encoded = json.dumps(
definition, sort_keys=True, separators=(",", ":"),
ensure_ascii=False, allow_nan=False,
).encode("utf-8")
created = client.managed_agents.create_managed_agent(
project,
agent_slug=agent_slug,
display_name="Support quickstart",
source=CreateManagedAgentSourceRequest(
content_digest="sha256:" + hashlib.sha256(encoded).hexdigest(),
definition=definition,
),
status="active",
)
print("Created agent:", created["managedAgent"])

Run creation once. If support-quickstart already exists, find it with client.managed_agents.list_managed_agents(project) and reuse it, or pick another slug. Do not repeat creation after an uncertain response.

3

Submit a task

Append this to the same file:

request_id = "quickstart-" + str(uuid.uuid4())
print("Request ID:", request_id, flush=True)
run = client.runs.start(
project,
agent_slug,
tenant_id="demo-customer",
user_id="demo-user",
idempotency_key=request_id,
input={
"text": (
"A customer reports two charges for the same order. "
"We have the order number but no transaction IDs. "
"Summarize the case and recommend the next step."
)
},
product_context={},
policy={},
)
print("Run:", run.run_id, "Status:", run.status, flush=True)

The response confirms admission, not completion. Keep the run ID.

If the request times out before a response, retry with the same request_id and identical input. A new ID means new work.

tenant_id and user_id identify the caller in your application. The demo values are fine here; in an application, derive them from your authenticated user.

4

Watch the result

Append this bounded polling loop, then run uv run first_agent.py:

cursor = "0"
deadline = time.monotonic() + 120
terminal = {"completed", "failed", "cancelled"}
while time.monotonic() < deadline:
page = client.runs.events(project, run.run_id, after=cursor)
for event in page.events:
print(event.event_type, event.payload)
cursor = str(page.next_after)
current = client.runs.get(project, run.run_id)
if current.status in terminal:
# Drain events committed between the page read and the status read.
while True:
page = client.runs.events(project, run.run_id, after=cursor)
for event in page.events:
print(event.event_type, event.payload)
cursor = str(page.next_after)
if not page.events:
break
print("Final status:", current.status)
break
if current.status == "waiting_for_tool":
print("Action needed:", client.runs.pending_actions(project, run.run_id))
break
time.sleep(1)
else:
print("Stopped waiting. Hosted work may still be running:", run.run_id)

A successful run emits a run.completed event with the output, and the final status is completed. The answer should name the duplicate-charge report, the missing transaction IDs, and a next step based on those facts. Wording varies by model.

The two-minute deadline only bounds polling; each HTTP request also has its own timeout. It does not cancel hosted work. A waiting action needs handling; see Runs and tool requests.

Do not log event payloads indiscriminately in production. They can contain customer data.

5

Inspect what happened

Use the same run ID to read retained execution evidence:

evidence = client.runs.get_trajectory(project, run.run_id)
print("Trajectory available for run:", evidence["runId"])

A trajectory is a permitted view of the retained execution structure. It is separate from the final answer and may be partial or unavailable. See Trace ingestion for missing measurements and dashboard navigation.

Using TypeScript

Install the TypeScript SDK with npm install @sikaru/sdk, then start work with an existing active agent:

import { SikaruApi } from "@sikaru/sdk";
const client = new SikaruApi({
apiKey: process.env.SIKARU_API_KEY!,
baseUrl: process.env.SIKARU_BASE_URL!,
});
const run = await client.runs.start(
process.env.SIKARU_PROJECT_ID!, "support-quickstart", {
tenant_id: "demo-customer",
user_id: "demo-user",
input: { text: "Summarize this case: an order has two charges and no transaction IDs." },
product_context: {},
policy: {},
},
);
console.log(run.runId);

Next steps