Skip to navigation

SDK configuration and async usage

Configure SDK timeouts and retries, use the async Python client, handle error responses, page through results, and poll self-hosted compute work.

View as Markdown

Use the authenticated client setup from Quickstart. The examples below read an existing run: set SIKARU_PROJECT_ID and SIKARU_RUN_ID to its identifiers.

SettingPythonTypeScript
ClientSikaruApi, AsyncSikaruApiSikaruApi
Client timeouttimeout (seconds)timeoutInSeconds
Retriesmax_retriesmaxRetries
Per-request overriderequest_options={"timeout": ...}{ timeoutInSeconds: ... }
Automatic retriesGET and HEAD onlyGET and HEAD only

Make async requests in Python

Use AsyncSikaruApi in an async application. Supply an async HTTP client when you need explicit connection cleanup or transport configuration.

import asyncio
import os
import httpx
from sikaru_api import AsyncSikaruApi
async def main():
async with httpx.AsyncClient(timeout=20) as transport:
client = AsyncSikaruApi(
api_key=os.environ["SIKARU_API_KEY"],
base_url=os.environ["SIKARU_BASE_URL"],
httpx_client=transport,
timeout=20,
max_retries=0,
)
run = await client.runs.get(
os.environ["SIKARU_PROJECT_ID"], os.environ["SIKARU_RUN_ID"],
request_options={"timeout": 10},
)
print(run.status)
asyncio.run(main())

The synchronous SikaruApi accepts the same timeout and retry options, with httpx.Client for its transport. Python timeouts are in seconds. Per-request timeout and max_retries override client defaults.

A request timeout limits one HTTP call. It does not set an overall observation deadline, and it does not cancel a hosted run.

Handle errors and raw responses

from sikaru_api.core.api_error import ApiError
try:
response = client.runs.with_raw_response.get(project, run_id)
print(response.status_code)
print(response.data.status)
except ApiError as error:
print("Sikaru request failed:", error.status_code)

Here client is a synchronous client and run_id is an existing run ID. Raw responses also expose headers. Handle network and timeout errors from the HTTP transport separately. Log only the response fields you need for diagnosis: bodies and headers can contain customer data.

ResponseApplication action
401 or 403Check the key, project scope, and permission required by the operation.
404Check the identifier and its project ownership.
402Billing refused the request (insufficient_credits). Check the plan, credits and the agent’s spending cap.
409Branch on the body’s code, such as idempotency_conflict. Read the retained state or receipt before retrying.
422Correct the request using the endpoint schema and error details.
429 or 5xxApply bounded retry handling for reads; reconcile mutations before submitting them again.

Error responses have the body {"detail": ..., "code": ...}. 422 validation errors list invalid fields in detail instead.

  • code is specific where one applies, such as idempotency_conflict. Otherwise it is a status default such as not_found.
  • In Python, read error.body.code and error.headers["retry-after"].
  • A 429 or 503 refusal with a code includes Retry-After in seconds.
  • A failed run is not an error response. Read error.code and error.recoverable on the run itself. See Runs and tool requests.

Only GET and HEAD requests retry automatically. Setting retry options does not enable automatic mutation replay. Keep idempotency keys stable for identical submissions when the endpoint supports them.

Set TypeScript request options

import { SikaruApi } from "@sikaru/sdk";
const client = new SikaruApi({
apiKey: process.env.SIKARU_API_KEY!,
baseUrl: process.env.SIKARU_BASE_URL!,
timeoutInSeconds: 20,
maxRetries: 0,
});
const run = await client.runs.get(
process.env.SIKARU_PROJECT_ID!, process.env.SIKARU_RUN_ID!,
{ timeoutInSeconds: 10 },
);
console.log(run.status);

Keep the key in server-side code. Use your language client’s reference for error types and request-option names. They are not identical across languages.

Page through results and events

Pagination is endpoint-specific:

ListingCursor parameter
Sessions, objectivesafter
Evaluation jobs, evaluation resultscursor
Run events (runs.events, Python)after in, next_after out

Read each response envelope and pass its continuation cursor to the same endpoint, keeping the same filters. Do not assume these clients automatically read every page.

For run events, persist the cursor and pass it as after on the next JSON page. Deduplicate by event identity if a page arrives again. runs.events returns a JSON page. For the dedicated SSE iterator, use runs.stream_events in Python or runs.streamEvents in TypeScript. See Runs and tool requests.

Poll self-hosted compute with JSON

Each role uses ordinary generated HTTP methods, without requiring SSE support:

RoleWhat it doesMethod
ControllerBinds an execution session, claims it, and issues a restricted credentialcompute_attachments.create
WorkerPolls for one environmentcompute_workers.poll
ExecutorPolls for its own attachmentcompute_operations.poll

An executor can inspect its scoped work page:

from sikaru_api import SikaruApi
executor = SikaruApi(base_url=api_url, api_key=attachment_token)
page = executor.compute_operations.poll(project_id, attachment_id, wait_seconds=0)
# Empty operations are not completion; inspect the execution summary separately.
print(page.execution_phase)

The native executor owns readiness, monotonic lease deadlines, process supervision, fsynced intents, and immutable receipt submission. Use sikaru compute serve in your sandbox unless you implement that entire executor contract. Never pass a controller credential to the sandbox.

See Local compute for bootstrap fields, approvals, file boundaries, and recovery.

Next steps