Remote client (Tier 4)
Drives a hosted Kendra Orchestrator engine over HTTP. Optional — nothing in Tiers 1-3 depends on it.
Requires the [remote] extra.
pip install "korchestrator[remote]"
KorchestratorClient
KorchestratorClient(
base_url: str,
*,
api_key: str | None = None,
timeout: float = DEFAULT_TIMEOUT_SECONDS,
max_retries: int = DEFAULT_MAX_RETRIES,
)
Thin client for a hosted Korchestrator engine (spec 04 §7, Tier 4, the [remote] extra).
Speaks the documented remote contract over HTTP: one Authorization: Bearer header for
both a static API key and a Keycloak/KIAM JWT (spec 04 §7.2, ADR 0005), a 30s default
per-request timeout (overridable per call), and up to 3 retries with full-jitter exponential
backoff on 429/502/503/504 and connection failures — never on any other 4xx, since retrying a
client error is a defect (spec 04 §7.5). Covers run lifecycle (run/run_swarm/
get_run/wait/run_and_wait/list_runs/get_run_summary), control and identity
(resume/cancel/edit_resume/me/my_quota/my_runs/key management),
discovery (tools/models/swarm_templates), and live event streaming (stream, a
native async iterator) — every method except stream is a sync wrapper around an async core
(spec 04 §7's own Tier-4 example calls client.run_and_wait(...) with no await). Nothing
in Tiers 1-3 (Korch/Swarm/the kernel) depends on this client, and the base install
never imports it.
Example
from korchestrator.remote import KorchestratorClient client = KorchestratorClient("https://engine.example.com", api_key="sk-example") client.close()
Build a client bound to base_url, authenticating with api_key when given.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
base_url
|
str
|
The engine's base URL, e.g. |
required |
api_key
|
str | None
|
A static per-tenant key or a Keycloak/KIAM JWT — both ride the same
|
None
|
timeout
|
float
|
The default per-request timeout in seconds; overridable per call. |
DEFAULT_TIMEOUT_SECONDS
|
max_retries
|
int
|
How many times a retryable failure is retried before raising. |
DEFAULT_MAX_RETRIES
|
__aenter__
async
__aenter__() -> Self
Support async with KorchestratorClient(...) as client:.
__aexit__
async
__aexit__(
exc_type: type[BaseException] | None,
exc: BaseException | None,
traceback: TracebackType | None,
) -> None
Close the underlying connection pool on exit.
__repr__
__repr__() -> str
Show base_url only — never the credential (spec 04 §7.2: never logged/printed).
aclose
async
aclose() -> None
Close the underlying connection pool (async).
cancel
cancel(
run_id: str, *, timeout: float | None = None
) -> RemoteRunResult
Cancel a run (POST /v1/run/{id}/cancel).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
run_id
|
str
|
The run to cancel. |
required |
timeout
|
float | None
|
Overrides the client's default timeout for this call only. |
None
|
Returns:
| Type | Description |
|---|---|
RemoteRunResult
|
The run's :class: |
Raises:
| Type | Description |
|---|---|
ApiError
|
The engine rejected the request or the run does not exist. |
NetworkError
|
The connection failed after retries were exhausted. |
TimeoutError
|
The request timed out after retries were exhausted. |
Example
from korchestrator.remote import KorchestratorClient client = KorchestratorClient("https://engine.example.com", api_key="sk-example") client.cancel("r1") # doctest: +SKIP client.close()
close
close() -> None
Close the underlying connection pool (sync convenience wrapper around :meth:aclose).
create_key
create_key(
*,
scopes: Sequence[str] = (),
timeout: float | None = None,
) -> ApiKey
Create a new API key (POST /v1/keys, the korchestrator:admin scope).
The returned secret is shown once — the engine never returns it again.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
scopes
|
Sequence[str]
|
The scopes to grant the new key. |
()
|
timeout
|
float | None
|
Overrides the client's default timeout for this call only. |
None
|
Returns:
| Type | Description |
|---|---|
ApiKey
|
The newly created :class: |
Raises:
| Type | Description |
|---|---|
ApiError
|
The engine rejected the request (e.g. insufficient scope). |
NetworkError
|
The connection failed after retries were exhausted. |
TimeoutError
|
The request timed out after retries were exhausted. |
Example
from korchestrator.remote import KorchestratorClient client = KorchestratorClient("https://engine.example.com", api_key="sk-example") client.create_key(scopes=["korchestrator:read"]) # doctest: +SKIP client.close()
edit_resume
edit_resume(
run_id: str,
*,
updates: Mapping[str, JSONValue] | None = None,
trust_delta: float = 0.0,
timeout: float | None = None,
) -> RemoteRunResult
Modify a governance_paused run's state and resume it (POST .../edit-resume).
Mirrors the local kernel's own edit_resume signal (services.Korch.edit_resume):
updates are merged last-value into the run's context channel, and trust_delta is
folded into trust_score.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
run_id
|
str
|
The paused run to edit and resume. |
required |
updates
|
Mapping[str, JSONValue] | None
|
Context-channel values to merge (last-value) into the paused run's state. |
None
|
trust_delta
|
float
|
Folded into |
0.0
|
timeout
|
float | None
|
Overrides the client's default timeout for this call only. |
None
|
Returns:
| Type | Description |
|---|---|
RemoteRunResult
|
The run's :class: |
Raises:
| Type | Description |
|---|---|
ApiError
|
The engine rejected the request or the run is not paused. |
NetworkError
|
The connection failed after retries were exhausted. |
TimeoutError
|
The request timed out after retries were exhausted. |
Example
from korchestrator.remote import KorchestratorClient client = KorchestratorClient("https://engine.example.com", api_key="sk-example") client.edit_resume("r1", trust_delta=0.1) # doctest: +SKIP client.close()
get_run
get_run(
run_id: str, *, timeout: float | None = None
) -> RemoteRunResult
Fetch a run's full live state (GET /v1/run/{id}).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
run_id
|
str
|
The run to fetch. |
required |
timeout
|
float | None
|
Overrides the client's default timeout for this call only. |
None
|
Returns:
| Type | Description |
|---|---|
RemoteRunResult
|
The run's current :class: |
Raises:
| Type | Description |
|---|---|
ApiError
|
The engine rejected the request or the run does not exist. |
NetworkError
|
The connection failed after retries were exhausted. |
TimeoutError
|
The request timed out after retries were exhausted. |
Example
from korchestrator.remote import KorchestratorClient client = KorchestratorClient("https://engine.example.com", api_key="sk-example") client.get_run("r1") # doctest: +SKIP client.close()
get_run_summary
get_run_summary(
run_id: str, *, timeout: float | None = None
) -> RunSummary
Fetch a run's summary (GET /v1/runs/{id}/summary).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
run_id
|
str
|
The run to summarize. |
required |
timeout
|
float | None
|
Overrides the client's default timeout for this call only. |
None
|
Returns:
| Type | Description |
|---|---|
RunSummary
|
The run's :class: |
Raises:
| Type | Description |
|---|---|
ApiError
|
The engine rejected the request or the run does not exist. |
NetworkError
|
The connection failed after retries were exhausted. |
TimeoutError
|
The request timed out after retries were exhausted. |
Example
from korchestrator.remote import KorchestratorClient client = KorchestratorClient("https://engine.example.com", api_key="sk-example") client.get_run_summary("r1") # doctest: +SKIP client.close()
list_keys
list_keys(
*, timeout: float | None = None
) -> tuple[ApiKeySummary, ...]
List existing API keys (GET /v1/keys, the korchestrator:admin scope).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timeout
|
float | None
|
Overrides the client's default timeout for this call only. |
None
|
Returns:
| Type | Description |
|---|---|
ApiKeySummary
|
The tenant's keys as :class: |
...
|
secret, which the engine only ever returns once, at creation. |
Raises:
| Type | Description |
|---|---|
ApiError
|
The engine rejected the request (e.g. insufficient scope). |
NetworkError
|
The connection failed after retries were exhausted. |
TimeoutError
|
The request timed out after retries were exhausted. |
Example
from korchestrator.remote import KorchestratorClient client = KorchestratorClient("https://engine.example.com", api_key="sk-example") client.list_keys() # doctest: +SKIP client.close()
list_runs
list_runs(
*,
tenant_id: str | None = None,
timeout: float | None = None,
) -> tuple[RunSummary, ...]
List runs visible to the caller (GET /v1/runs).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
tenant_id
|
str | None
|
Overrides the tenant derived from the API key, when authorized. |
None
|
timeout
|
float | None
|
Overrides the client's default timeout for this call only. |
None
|
Returns:
| Type | Description |
|---|---|
tuple[RunSummary, ...]
|
The visible runs as :class: |
Raises:
| Type | Description |
|---|---|
ApiError
|
The engine rejected the request. |
NetworkError
|
The connection failed after retries were exhausted. |
TimeoutError
|
The request timed out after retries were exhausted. |
Example
from korchestrator.remote import KorchestratorClient client = KorchestratorClient("https://engine.example.com", api_key="sk-example") client.list_runs() # doctest: +SKIP client.close()
me
me(*, timeout: float | None = None) -> CallerIdentity
Fetch the authenticated caller's identity (GET /v1/me).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timeout
|
float | None
|
Overrides the client's default timeout for this call only. |
None
|
Returns:
| Type | Description |
|---|---|
CallerIdentity
|
The caller's :class: |
Raises:
| Type | Description |
|---|---|
ApiError
|
The engine rejected the request. |
NetworkError
|
The connection failed after retries were exhausted. |
TimeoutError
|
The request timed out after retries were exhausted. |
Example
from korchestrator.remote import KorchestratorClient client = KorchestratorClient("https://engine.example.com", api_key="sk-example") client.me() # doctest: +SKIP client.close()
models
models(
*, timeout: float | None = None
) -> tuple[ModelCard, ...]
List the models available on the engine (GET /v1/models).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timeout
|
float | None
|
Overrides the client's default timeout for this call only. |
None
|
Returns:
| Type | Description |
|---|---|
ModelCard
|
The available models as :class: |
...
|
catalogue shape the local kernel's routing already uses. |
Raises:
| Type | Description |
|---|---|
ApiError
|
The engine rejected the request. |
NetworkError
|
The connection failed after retries were exhausted. |
TimeoutError
|
The request timed out after retries were exhausted. |
Example
from korchestrator.remote import KorchestratorClient client = KorchestratorClient("https://engine.example.com", api_key="sk-example") client.models() # doctest: +SKIP client.close()
my_quota
my_quota(*, timeout: float | None = None) -> Quota
Fetch the authenticated caller's usage quota (GET /v1/me/quota).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timeout
|
float | None
|
Overrides the client's default timeout for this call only. |
None
|
Returns:
| Type | Description |
|---|---|
Quota
|
The caller's :class: |
Raises:
| Type | Description |
|---|---|
ApiError
|
The engine rejected the request. |
NetworkError
|
The connection failed after retries were exhausted. |
TimeoutError
|
The request timed out after retries were exhausted. |
Example
from korchestrator.remote import KorchestratorClient client = KorchestratorClient("https://engine.example.com", api_key="sk-example") client.my_quota() # doctest: +SKIP client.close()
my_runs
my_runs(
*, timeout: float | None = None
) -> tuple[RunSummary, ...]
List the authenticated caller's runs (GET /v1/me/runs).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timeout
|
float | None
|
Overrides the client's default timeout for this call only. |
None
|
Returns:
| Type | Description |
|---|---|
tuple[RunSummary, ...]
|
The caller's runs as :class: |
Raises:
| Type | Description |
|---|---|
ApiError
|
The engine rejected the request. |
NetworkError
|
The connection failed after retries were exhausted. |
TimeoutError
|
The request timed out after retries were exhausted. |
Example
from korchestrator.remote import KorchestratorClient client = KorchestratorClient("https://engine.example.com", api_key="sk-example") client.my_runs() # doctest: +SKIP client.close()
resume
resume(
run_id: str, *, timeout: float | None = None
) -> RemoteRunResult
Resume a governance_paused run (POST /v1/run/{id}/resume).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
run_id
|
str
|
The paused run to resume. |
required |
timeout
|
float | None
|
Overrides the client's default timeout for this call only. |
None
|
Returns:
| Type | Description |
|---|---|
RemoteRunResult
|
The run's :class: |
Raises:
| Type | Description |
|---|---|
ApiError
|
The engine rejected the request or the run is not paused. |
NetworkError
|
The connection failed after retries were exhausted. |
TimeoutError
|
The request timed out after retries were exhausted. |
Example
from korchestrator.remote import KorchestratorClient client = KorchestratorClient("https://engine.example.com", api_key="sk-example") client.resume("r1") # doctest: +SKIP client.close()
revoke_key
revoke_key(
key_id: str, *, timeout: float | None = None
) -> None
Revoke an API key (DELETE /v1/keys/{id}, the korchestrator:admin scope).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
key_id
|
str
|
The key to revoke. |
required |
timeout
|
float | None
|
Overrides the client's default timeout for this call only. |
None
|
Raises:
| Type | Description |
|---|---|
ApiError
|
The engine rejected the request or the key does not exist. |
NetworkError
|
The connection failed after retries were exhausted. |
TimeoutError
|
The request timed out after retries were exhausted. |
Example
from korchestrator.remote import KorchestratorClient client = KorchestratorClient("https://engine.example.com", api_key="sk-example") client.revoke_key("key-1") # doctest: +SKIP client.close()
run
run(
objective: str,
*,
max_supersteps: int = 10,
mock_mode: bool = False,
tenant_id: str | None = None,
timeout: float | None = None,
) -> RemoteRunResult
Start a run; the engine plans the graph (POST /v1/run/auto).
Returns as soon as the engine has accepted the run — typically status="started" or
"running", not necessarily terminal. Use :meth:wait or :meth:run_and_wait to block
until a terminal state.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
objective
|
str
|
The goal, at least 10 characters. |
required |
max_supersteps
|
int
|
Hard halt bound for the run. |
10
|
mock_mode
|
bool
|
Run with a deterministic mock model (spec 04 §7.1). |
False
|
tenant_id
|
str | None
|
Overrides the tenant derived from the API key, when the caller is authorized to act cross-tenant. |
None
|
timeout
|
float | None
|
Overrides the client's default timeout for this call only. |
None
|
Returns:
| Type | Description |
|---|---|
RemoteRunResult
|
The run's initial :class: |
Raises:
| Type | Description |
|---|---|
ApiError
|
The engine rejected or failed the request. |
NetworkError
|
The connection failed after retries were exhausted. |
TimeoutError
|
The request timed out after retries were exhausted. |
Example
from korchestrator.remote import KorchestratorClient client = KorchestratorClient("https://engine.example.com", api_key="sk-example") client.run("Summarize the quarterly incident reports") # doctest: +SKIP client.close()
run_and_wait
run_and_wait(
objective: str,
*,
max_supersteps: int = 10,
mock_mode: bool = False,
tenant_id: str | None = None,
poll_interval: float = DEFAULT_POLL_INTERVAL_SECONDS,
timeout: float | None = None,
) -> RemoteRunResult
Start a run and block until it reaches a terminal state (run + wait).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
objective
|
str
|
The goal, at least 10 characters. |
required |
max_supersteps
|
int
|
Hard halt bound for the run. |
10
|
mock_mode
|
bool
|
Run with a deterministic mock model. |
False
|
tenant_id
|
str | None
|
Overrides the tenant derived from the API key, when authorized. |
None
|
poll_interval
|
float
|
Seconds between polls while waiting. |
DEFAULT_POLL_INTERVAL_SECONDS
|
timeout
|
float | None
|
Per-request timeout passed to the start call and every poll. |
None
|
Returns:
| Type | Description |
|---|---|
RemoteRunResult
|
The terminal :class: |
Raises:
| Type | Description |
|---|---|
ApiError
|
The engine rejected or failed the request. |
NetworkError
|
The connection failed after retries were exhausted. |
TimeoutError
|
A request timed out after retries were exhausted. |
Example
from korchestrator.remote import KorchestratorClient client = KorchestratorClient("https://engine.example.com", api_key="sk-example") client.run_and_wait("Summarize Q3 incident reports") # doctest: +SKIP client.close()
run_swarm
run_swarm(
agents: Sequence[AgentConfig],
edges: Sequence[tuple[str, str]] = (),
*,
objective: str,
max_supersteps: int = 10,
tenant_id: str | None = None,
timeout: float | None = None,
) -> RemoteRunResult
Start a run with an explicit graph (POST /v1/run/swarm).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
agents
|
Sequence[AgentConfig]
|
The declared agents, as the same :class: |
required |
edges
|
Sequence[tuple[str, str]]
|
|
()
|
objective
|
str
|
The goal, at least 10 characters. |
required |
max_supersteps
|
int
|
Hard halt bound for the run. |
10
|
tenant_id
|
str | None
|
Overrides the tenant derived from the API key, when authorized. |
None
|
timeout
|
float | None
|
Overrides the client's default timeout for this call only. |
None
|
Returns:
| Type | Description |
|---|---|
RemoteRunResult
|
The run's initial :class: |
Raises:
| Type | Description |
|---|---|
ApiError
|
The engine rejected or failed the request. |
NetworkError
|
The connection failed after retries were exhausted. |
TimeoutError
|
The request timed out after retries were exhausted. |
Example
from korchestrator.models import AgentConfig, AgentPersona from korchestrator.remote import KorchestratorClient client = KorchestratorClient("https://engine.example.com", api_key="sk-example") agent = AgentConfig(id="lead", persona=AgentPersona(role="lead")) client.run_swarm([agent], objective="Review this PR") # doctest: +SKIP client.close()
stream
async
stream(
run_id: str, *, timeout: float | None = None
) -> AsyncIterator[RunEvent]
Stream a run's live events (GET /v1/run/{id}/stream, Server-Sent Events).
Unlike every other method on this class, stream is a native async generator — SSE is
inherently incremental, so wrapping it in :func:asyncio.run would defeat the point
(spec 04 §7.5: "Streaming: SSE, exposed as an async iterator").
Reconnects automatically (up to max_retries consecutive failures, the same
full-jitter backoff :meth:_request uses) if the connection drops before the engine
closes the stream. The wire format (:class:~korchestrator.models.remote.RunEvent, one
SSE frame per event) carries no event id, so a reconnect resumes from "now", not from the
last event actually delivered — events emitted while disconnected are not replayed. The
generator returns normally once the engine closes the stream (the run reached a terminal
state).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
run_id
|
str
|
The run to stream. |
required |
timeout
|
float | None
|
Overrides the client's default timeout for this call only. |
None
|
Yields:
| Name | Type | Description |
|---|---|---|
Each |
AsyncIterator[RunEvent]
|
class: |
Raises:
| Type | Description |
|---|---|
ApiError
|
The engine rejected the request or the run does not exist. |
NetworkError
|
The connection failed after retries were exhausted. |
TimeoutError
|
The connection timed out after retries were exhausted. |
Example
import asyncio from korchestrator.remote import KorchestratorClient async def _demo(): ... client = KorchestratorClient( ... "https://engine.example.com", api_key="sk-example" ... ) ... async for event in client.stream("r1"): ... print(event.name) ... await client.aclose() asyncio.run(_demo()) # doctest: +SKIP
swarm_templates
swarm_templates(
*, timeout: float | None = None
) -> tuple[SwarmTemplate, ...]
List the engine's swarm topology presets (GET /v1/swarm-templates).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timeout
|
float | None
|
Overrides the client's default timeout for this call only. |
None
|
Returns:
| Type | Description |
|---|---|
tuple[SwarmTemplate, ...]
|
The available presets as :class: |
Raises:
| Type | Description |
|---|---|
ApiError
|
The engine rejected the request. |
NetworkError
|
The connection failed after retries were exhausted. |
TimeoutError
|
The request timed out after retries were exhausted. |
Example
from korchestrator.remote import KorchestratorClient client = KorchestratorClient("https://engine.example.com", api_key="sk-example") client.swarm_templates() # doctest: +SKIP client.close()
tools
tools(
*, timeout: float | None = None
) -> tuple[ToolDescriptor, ...]
List the tools available on the engine (GET /v1/tools).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timeout
|
float | None
|
Overrides the client's default timeout for this call only. |
None
|
Returns:
| Type | Description |
|---|---|
tuple[ToolDescriptor, ...]
|
The available tools as :class: |
Raises:
| Type | Description |
|---|---|
ApiError
|
The engine rejected the request. |
NetworkError
|
The connection failed after retries were exhausted. |
TimeoutError
|
The request timed out after retries were exhausted. |
Example
from korchestrator.remote import KorchestratorClient client = KorchestratorClient("https://engine.example.com", api_key="sk-example") client.tools() # doctest: +SKIP client.close()
wait
wait(
run_id: str,
*,
poll_interval: float = DEFAULT_POLL_INTERVAL_SECONDS,
timeout: float | None = None,
) -> RemoteRunResult
Block until run_id reaches a terminal state, polling :meth:get_run.
A governance_paused run is not terminal — it stays pending until an operator calls
:meth:resume/cancel/edit_resume (P9.4), so this keeps polling through it rather
than returning early.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
run_id
|
str
|
The run to wait for. |
required |
poll_interval
|
float
|
Seconds between polls. |
DEFAULT_POLL_INTERVAL_SECONDS
|
timeout
|
float | None
|
Per-request timeout passed to each poll; does not bound the total wait. |
None
|
Returns:
| Type | Description |
|---|---|
RemoteRunResult
|
The terminal :class: |
Raises:
| Type | Description |
|---|---|
ApiError
|
The engine rejected the request or the run does not exist. |
NetworkError
|
The connection failed after retries were exhausted. |
TimeoutError
|
A poll request timed out after retries were exhausted. |
Example
from korchestrator.remote import KorchestratorClient client = KorchestratorClient("https://engine.example.com", api_key="sk-example") client.wait("r1") # doctest: +SKIP client.close()
Wire-facing models
Distinct from the local kernel's own models — RemoteRunResult has no nested AgentState, for
example, since that's an internal, non-serialised kernel detail the remote contract never exposes.
RemoteRunResult
Bases: BaseModel
A run's outcome as the remote engine reports it — terminal, paused, or still running.
Returned by :meth:KorchestratorClient.run, run_swarm, get_run, wait, and
run_and_wait (spec 04 §7.3's POST /v1/run/auto, POST /v1/run/swarm,
GET /v1/run/{id}).
RunSummary
Bases: BaseModel
A lightweight run summary — GET /v1/runs/{id}/summary and the terminal-state webhook.
Returned by :meth:KorchestratorClient.get_run_summary and, as a tuple, list_runs.
RunEvent
Bases: BaseModel
One live event from a run's SSE stream (GET /v1/run/{id}/stream, spec 04 §7.3/§7.5).
Deliberately mirrors :class:korchestrator.events.Event's shape (name/payload/
run_id) — the same concept, one streamed event — without importing across the
clients/events module boundary spec 05's allowed-imports table doesn't authorize
(clients/ reuses the same purpose-built-model pattern this file already uses for
:class:RemoteRunResult rather than the local kernel's RunResult).
CallerIdentity
Bases: BaseModel
The authenticated caller's identity (GET /v1/me, spec 04 §7.3).
Quota
Bases: BaseModel
The caller's usage quota (GET /v1/me/quota, spec 04 §7.3).
ApiKey
Bases: BaseModel
A newly created API key (POST /v1/keys, spec 04 §7.3).
The secret is returned once, at creation — the engine never returns it again, matching every
common API-key UX. key is a :class:~pydantic.SecretStr so an accidental repr/str
(a log line, a stray print) never leaks it; call key.get_secret_value() to use it.
ApiKeySummary
Bases: BaseModel
An existing API key's metadata (GET /v1/keys, spec 04 §7.3) — never the secret.
ToolDescriptor
Bases: BaseModel
A discoverable tool (GET /v1/tools, spec 04 §7.3).
The wire twin of the local :class:korchestrator.interfaces.Connector protocol's
name/description/schema (P6) — the same concept the AUB registry already
exposes locally, described for a remote caller instead. The field is named
input_schema, not schema — BaseModel reserves schema for its own (deprecated)
.schema() method, and input_schema matches Anthropic's own tool-use vocabulary.
SwarmTemplate
Bases: BaseModel
A named swarm topology preset (GET /v1/swarm-templates, spec 04 §7.3).
Reuses :class:~korchestrator.models.agent.AgentConfig for agents — the same declarative
shape run_swarm already accepts, so a template can be fetched and passed straight through.
ApiError
ApiError(
message: str,
*,
status: int = 500,
code: str | None = None,
trace_id: str | None = None,
)
Bases: KorchError
A :class:~korchestrator.remote.KorchestratorClient call failed (spec 04 §7.5).
Raised for any non-2xx response the remote engine returns after retries are exhausted —
status and trace_id let a caller correlate the failure with server-side logs and
support without parsing the message text.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
message
|
str
|
An actionable description of the failure. |
required |
status
|
int
|
The HTTP status code the engine returned. Defaults to |
500
|
code
|
str | None
|
The stable error code — the engine's own code when its response body carries one,
else :attr: |
None
|
trace_id
|
str | None
|
The engine's request trace id, when the response provided one. |
None
|
Example
from korchestrator.exceptions import ApiError, KorchError err = ApiError("Run 'r1' not found.", status=404, trace_id="trace-abc") err.status, err.trace_id, isinstance(err, KorchError) (404, 'trace-abc', True)
Build the error with the engine's HTTP status and optional trace id.