SDK
There is a first-party TypeScript client for this API. It is not on npm, so build against the HTTP contract, and read the versioning rule below before you pin anything.
Availability
Section titled “Availability”@wamp/app-sdk is maintained in the WAMP repository. A registry check on
September 8, 2026 returned 404 for the public npm package. Use the HTTP
examples in this site, or obtain a packed package from your platform operator.
Do not depend on an unpublished package name in deployment instructions.
Working without it costs little: every operation on this site is plain HTTPS
against the OpenAPI contract, and the only part that is not a
fetch call is signing the app assertion, which is about ten lines of jose.
Authentication shows it.
What a version number means
Section titled “What a version number means”The major version is the Cloud API generation the client speaks. 1.x speaks
Cloud v1, the API this site documents; a Cloud v2 would ship as 2.x. Minor
and patch releases are SDK-only — added methods, added exported types, fixes —
and never move you to a different API generation.
So pin on the major (^1.0.0) if what you care about is the wire contract, and
read a major bump as “the API generation moved”, not as “the client was
rewritten”. The corollary is the useful part: a 1.x upgrade cannot change which
endpoints you are calling.
Why the client is worth using when it ships
Section titled “Why the client is worth using when it ships”Authenticated operations in the OpenAPI contract carry an
x-wamp-sdk-method extension naming their client method. A test checks that
mapping in both directions. The two
without one are the unauthenticated discovery pair, GET /v1/openapi.json and
GET /v1/docs. So the client cannot quietly fall behind the API, and the API
cannot gain an operation the client silently lacks. That is the same reason the
reference pages on this site are generated from the contract rather than
written: the contract is the one artifact everything else is checked against.
The mapping is data, not just a test fixture: WAMP_CLOUD_V1_SDK_OPERATIONS is
exported as a table of [method, path, client method] rows, so a backend that
audits its own coverage can read it rather than transcribe it.
The surface
Section titled “The surface”Three classes and two error types.
WampApp handles identity — the pieces you need before any Cloud call:
| Member | Purpose |
|---|---|
generateAppKeypair() |
One-time Ed25519 key generation. Register the public half; the private half never leaves your backend |
new WampApp(options) |
Holds your app slug and private key |
issueUserToken(options) |
Sign an end-user session token for a client to send to the AI proxy |
installationToken() |
Mint the tenant- and resource-exact backend token |
createInstallationIntent() / getInstallationIntent() |
Drive the installation handshake |
buildAssertion() |
Build the signed assertion the token exchange consumes |
WampCloud is the API client. Its methods map onto the operations documented
under Operations:
| Area | Methods |
|---|---|
| Discovery and input | capabilities, transcribeAudio |
| Native identity | me — first-party Desktop Cloud only; an installation credential cannot call it |
| Release probes | activateRuntimeReleaseProbe, deactivateRuntimeReleaseProbe — requires wamp.cloud.runtime-releases:probe |
| Sessions | createSession, getSession, updateSession, listSessions, archiveSession, restoreSessionWorkspace, inspectSessionExecution |
| Organization environments | listEnvironments, getEnvironment, listEnvironmentRevisions, putEnvironment, restoreEnvironment, archiveEnvironment, unarchiveEnvironment, putEnvironmentSecret, deleteEnvironmentSecret, putEnvironmentArchive, setDefaultEnvironment |
| Turns and runs | submitTurn, listTurns, getRun, cancelRun |
| Following work | listSessionEvents, sessionEvents, streamSessionEvents, streamSessionChanges, listOpenInteractions, decideInteraction |
| Artifacts | listArtifacts, getArtifact, getArtifactText, getArtifactContent |
| Repositories | listRepositories, listRepositoryGrants, resolveRepositoryGrant, reviewRepository |
| Publications | publishRepository, listPublications, getPublication, mergePublication, listPublicationMerges, getPublicationMerge |
transcribeAudio accepts bounded audio bytes, MIME type, and duration (100 ms
to 10 minutes, at most 20 MiB), and returns text. WAMP does not persist the
source audio; treat the returned text as ordinary user input and apply your
product’s normal review/send policy to it.
me exists on the Node client so the same class can serve the first-party
native token. It is not an integration method.
CloudInteraction.request is typed as CloudInteractionRequest: questions for
ask_user, plan for exit_plan_mode, and approval with the complete action
for a live approval. The opened event carries approval metadata and deadline,
without action arguments; fetch open interactions before presenting a decision.
offeredApprovalChoices(request.approval) returns the choices Cloud accepts.
Pass a caller-owned idempotencyKey to decideInteraction and reuse it on
retry. When another answer already won, the cloud_interaction_conflict error’s
outcome holds that answer; without outcome the request is no longer waiting.
ACP questions expose stable field ids, typed option values,
defaults and constraints; submit their answer as a JSON object in the reply
Turn’s message. Each request member is optional,
because a caller that renders only one kind still has to compile against an
event carrying the other. Events has
the payload.
sessionEvents is the exception in that table: it is an async generator over the
event log rather than a single operation, so it drives the cursor loop for you
instead of returning one page. Three things stay yours, deliberately, and each is
one line:
- The cursor is
event.sequence. The generator holds no state between calls, because only your code knows when an event became durable on your side. Persist the last sequence you handled and pass it back asafter. - The bound is
break. A generator fetches only what is pulled, so leaving thefor awaitstops paging. There is nomaxEventsoption: a page cap makes “I stopped early” and “I reached the tail” indistinguishable, and a caller’s ownbreakdoes not. - A hole throws
WampCloudEventGapError. Sequences are gapless per session, and nothing prunes an event, so a page that does not start atafter + 1is a server-side invariant violation rather than a slow write or expired retention. The generator throws and your cursor stays where it was, so retrying asks for the same range again.error.afteris the cursor you came from anderror.firstSequenceis what the server actually served — report the pair, do not invent a cursor past it. There is deliberately noresumeAfter: every cursor on the far side of a hole discards the missing events permanently, and that is an operator’s decision to take with the facts in hand, never a client fallback.
restoreSessionWorkspace brings back an expired sandbox, and
inspectSessionExecution is an operational inspection aid, not part of the normal
follow loop.
streamSessionEvents(sessionId, { after, signal }) follows the same log live as
an AsyncIterable<CloudSessionEvent>. It checks sequence contiguity, resumes
with Last-Event-ID, refreshes an App-mode token after 401, and spreads
reconnects after server-side ends over 0–30 seconds. Save the last sequence
your handler committed; the iterator’s in-memory cursor cannot replace that
durable record. Abort its signal or break the loop to stop following.
isTerminalRunEvent(event, runId) recognizes the four terminal Run types.
streamSessionChanges({ after, signal }) follows every Session the
installation created over one connection, as an
AsyncIterable<{ change?: CloudSessionChange; watermark: number }>. A change
names a Session and the sequence its log reached; page that Session from your
own cursor. An item without change only moves the watermark; every stream
opens with one, so the first item also says the stream is open. Save
watermark after acting on change and pass it back as
after; the iterator reconnects with the newest watermark it holds, under the
same retry and spread rules as streamSessionEvents. It needs an installation
credential. See Follow many Sessions.
For a multi-tenant backend, construct one App-mode WampCloud per customer
installation and reuse it across that customer’s calls. Each client caches its
installation token, coalesces exchanges, and refreshes after a rejected token.
WampCloudError carries the API’s error code and status, so the handling
described in Errors applies unchanged.
WampCloudEventGapError is the second error type and it is not an API error: no
request failed, and it carries no code and no status. It is the SDK reporting that
the event page is not contiguous with the cursor you supplied. Events are not
pruned by a retention window; this is an invariant violation, not an expected
expiration outcome. Handle it where you handle
your cursor, not where you handle HTTP failures — instanceof WampCloudEventGapError before a generic WampCloudError branch, since neither
is a subclass of the other.
WampApp and WampCloud both apply a 30-second deadline to every network
request. Override it once with requestTimeoutMs, which must be an integer from
1 to 3 600 000 milliseconds — anything outside that range throws at construction rather than
failing later. Provide a constructor-level AbortSignal to cancel all in-flight
requests when your backend shuts down. Event-page reads also accept a per-call
signal.
Two audience constants are exported for callers that validate tokens themselves:
END_USER_TOKEN_AUDIENCE and WAMP_CLOUD_RESOURCE_AUDIENCE.
Forward-compatible event typing
Section titled “Forward-compatible event typing”Every public Cloud declaration is exported from the package root, including
CloudSessionContinuation, the retained timeline event types,
KnownCloudSessionEvent, and CloudSafeTimelineEvent.
Five value sets are exported as as const arrays, so they are enumerable at
runtime and not only in the type system:
| Export | Union | Additive? |
|---|---|---|
CLOUD_RUN_STOP_REASONS |
CloudRunStopReason |
yes |
KNOWN_CLOUD_RUN_ERROR_CODES |
KnownCloudRunErrorCode |
yes |
CLOUD_CONTINUATION_REASONS |
CloudContinuationReason |
yes |
CLOUD_SESSION_PHASES |
CloudSessionPhase |
no — closed |
THINKING_LEVELS |
ThinkingLevel |
no — closed |
Each native model’s thinkingLevels lists the levels its route accepts. When
the list is absent, that model has no reasoning-level control.
For the additive ones, treat an unrecognized value as unknown rather than
invalid: use isKnownCloudSessionEvent before an exhaustive switch over known
event members, and isKnownCloudRunErrorCode before branching on a terminal
run’s errorCode. Both let you safely ignore a value newer than your installed
SDK.
phase is the exception. CLOUD_SESSION_PHASES is the complete set the server
can serve — three producers write it and nothing else does — so an exhaustive
switch over it is legal, and a new value would be a contract change rather than
an additive one. It stays advisory for a different reason: phase may lag a
run’s terminal transition, so derive your state machine from run.status and use
phase to label what a session is doing between runs.