@erstan/sdk@0.1.0-beta.1, a JavaScript ESM package with
TypeScript declarations for Node.js 22+. See the quickstart
for current private-beta availability and installation.
Client configuration
Every method accepts request options as its last argument:
signal, timeoutMs,
and maxRetries. Waiting methods also accept waitTimeoutMs (default 300,000 ms)
and pollIntervalMs (default 1,000 ms). The wait deadline starts after launch or
continuation acceptance, or on entry to wait; it does not include submission.
traceEvents additionally accepts maxPages (default 1,000).
Convenience run/wait operations pin one credential for the sequence. Separate
calls use the provider’s current key. Erstan restricts run access to the exact
key that created the run, so replacing a key is not a recovery path for old runs.
Published Agents and runs
All methods below are onclient. Optional request options are omitted from
the table unless needed to distinguish a signature.
Run bodies contain
input, optional laneId, attachments, and
idempotencyKey. Select the Agent and lane intentionally; do not pick the first
available Agent automatically. Attachments use { name, type, base64 } or
{ name, type, storageKey }, subject to the lane policy and 25 MB request limit.
The SDK does not read local file paths or upload files implicitly. Runtime
control fields such as Skill selections do not belong in business input.
Continuation bodies include message and may include an idempotencyKey.
Always follow the returned run ID. See Run Agents
for continuation and lane constraints.
Waiting and human interactions
RunWaitResult.reason is completed, failed, cancelled, interaction,
waiting, or unknown_status. The result includes run; finalResponse is
typed as unknown. Failed Agent execution is a result, not an HTTP exception.
Only an actionable pending interaction can be answered. reply uses the
current interactionId plus message or structured answers; decideApproval
uses { interactionId, action: 'approve' | 'reject' }. Retained/resuming
interrupts and asynchronous batches keep polling. Other pauses and unknown
future statuses return control. Nothing auto-approves or answers for the user.
Aborting a request or timing out observation does not cancel remote work.
Persist accepted run IDs and resume with runs.wait. Cancellation is a separate
intentional call and cannot undo external effects that already occurred.
Durable trace paging
Trace queries acceptcursor, limit, eventTypes, includePayloads, and
payloadMaxChars. Payloads are opt-in and remain potentially sensitive even
after server redaction. Sequence values stay strings.
trace
with an explicit cursor for manual paging. Breaking iteration does not cancel
the run.
Agent and Skill authoring
context.get() returns workspaceId, actor, scopes, available teams, and
capabilities. Check the expected workspace before making changes. The beta SDK
requires stagedAuthoring: true and authoringContract: '2026-09-09.1' for
authoring. Preview additionally requires guardedPreviews; explicit Skill
selections also require draftSkillOverrides. An older or disabled server
raises ErstanCapabilityError before the authoring call. Published runtime
methods do not depend on staged-authoring support.
agents.list/get are authoring reads, not aliases for listPublished/getPublished.
Authoring list queries accept cursor, limit, and query. Pass nextCursor
unchanged for the next page; do not invent offset pagination. Catalog queries
and node fields follow the included TypeScript declarations and live guide.
Catalog discovery is currently unavailable to team-restricted keys; do not
broaden a key automatically to work around that restriction.
Agent creation requires a target teamId, name, and complete nodes and
edges. Updates replace supplied node/edge arrays in full; preserve unrelated
content and unknown graph fields. Agent validation accepts proposed content or
an agentId. Skill creation and updates use a complete packageJson; create
also requires name. Skill validation accepts { packageJson, ... }.
Preserve every related file, action declaration, and extension field. Full
offline JSON/ZIP codecs are in the separate @erstan/skill-package package.
Permissions and lifecycle
These are additive to current workspace/team permissions and server
capabilities. A key that can validate through REST also has authoring write
authority; it is not a validation-only credential for untrusted PR code.
Saving stages Skill content while the previous published package remains live.
Agent name, description, category, tags, difficulty, and estimated time stage
with the graph and promote together; behavior type stays immutable after first
publication. Validation, preview, and publication are independent operations.
Publishing does not require a successful test receipt or a particular workflow.
Publish required Skills explicitly before the Agent. Agent publication never
publishes dependencies for you. Publishing a shared Skill affects future
consumers, while snapshot-backed admitted runs and their continuations retain
their selected packages. Legacy runs without snapshot evidence cannot be
assumed to have that guarantee. Multiple resource writes are not an atomic
deployment.
Guards, idempotency, and preview
writeOptions requires { idempotencyKey }. guardedOptions requires both
{ revision, idempotencyKey }; the SDK sends the revision as If-Match.
Keep content and its returned revision together. Historical version reads are
read-only. After a 412 conflict, re-read and reconcile rather than replacing
the guard on stale local edits.
input, optional laneId, and optional top-level
skillVersions: [{ skillId, version }]. Each selected Skill requires edit
permission and must fit the Agent’s existing Skill policy. Unselected Skills
and child Agents retain published content. Preview never runs unsaved local
files, auto-publishes dependencies, or bypasses approvals. It seals the selected
graph; later edits or publication can fork and advance the version. Preview
can incur costs and external effects, so invoke it only deliberately.
For identical authoring intent, same-key response recovery is available for
24 hours; retained tombstones prevent duplicate dispatch afterward. This is
at-most-once dispatch, not multi-resource atomicity. A lost response,
authoring_outcome_unknown, or expired receipt requires reconciliation before
any new mutation. Never blindly generate a fresh key to repeat an uncertain
write, or reuse a key with changed content or guards.
Errors and retry behavior
ErstanError is the base error. ErstanAPIError exposes status, code,
details, requestId, eventId, and retryAfterMs when available. Subclasses
distinguish authentication, permission, not-found, validation, conflict,
capability, and rate-limit errors. Configuration, connection, timeout, abort,
and protocol errors also have distinct classes. ErstanWaitTimeoutError
includes runId and the last observed run when available; other observation
errors may also carry them. See API errors for server codes.
Safe reads retry transient network errors and HTTP 408/429/500/502/503/504.
Run starts and continuations retry only with a non-empty body idempotencyKey.
Cancellation is idempotent. Replies and approval decisions never retry
automatically; inspect the current interaction after uncertainty. Authoring
mutations use their explicit keys and guarded receipt contract. Authorization,
validation, and conflict errors are not resolved by automatic retry.
Advanced MCP access
listTools(query?, options?), callTool(name, args?, options?), and
request(method, params?, options?) target Erstan’s stateless JSON-response
/v1/mcp endpoint using the same API-key configuration. This is not a generic
MCP transport or OAuth client: SSE, sessions, and notifications are unsupported.
Tool calls are not automatically retried, and isError remains part of the
result. JSON-RPC failures raise ErstanMcpError from the MCP subpath.
Use the live tool schema: MCP Skill updates/publication use expectedVersion,
not REST revision headers, and MCP Skill mutations have no idempotency argument.
REST/SDK history and cancellation methods do not imply equivalent MCP tools.
For host-managed OAuth, use the plugin.