Skip to main content

Conversations and Runs

Deployment owners can query Agents and execution records in their own standalone instance to select a target Agent, observe a known Run, and read execution receipts. See Connect to an Instance and Authenticate for the address and instance token. All read requests below use X-Agent-Service-Token.

Read Scope​

The Agent list, Run list, Run details, and runtime state are instance data reads for the instance owner. They do not provide per-user isolation between multiple tenants. Receipt reads additionally match the trusted identity resolved by the server to the Run's user ownership; both a missing Run and a Run belonging to another user return 404.

Agent IDs, Run IDs, user_id, and conversation_id identify records; they are not access credentials. Supplying a user ID, knowing a Run ID, or having seen a record elsewhere does not replace authentication and the endpoint's ownership checks.

List Agents​

GET /api/agents​

No request body, pagination, or filter parameters. A successful response is { "agents": [...] }. Items are summaries rather than full Agent configurations.

curl --silent --show-error \
--header "X-Agent-Service-Token: ${AGENT_SERVICE_TOKEN}" \
"${BASE_URL}/api/agents"

Example response structure:

{
"agents": [
{
"id": "your-agent-id",
"name": "Example Agent",
"skillsCount": 0,
"toolsCount": 0,
"heartbeatEnabled": false,
"hasGit": false,
"isCoreAgent": false,
"status": "idle"
}
]
}
FieldType and meaning
id, nameRequired strings; use id for other API calls, not the display name
skillsCount, toolsCountRequired nonnegative numbers; skill and tool counts in the summary
heartbeatEnabled, hasGit, isCoreAgentRequired booleans for heartbeat, a Git repository, and core Agent identity
statusOptional: online, busy, idle, offline, error, recovery, or shutdown
metadataErrorOptional: missing, unreadable, invalid_json, or invalid_shape; names, descriptions, and counts may be fallback values when present, so ask the administrator to repair configuration
description, engine, hasRemote, syncStatusOptional description, engine, upstream repository, and synchronization information
ui, avatar, avatarImageOptional UI and avatar summaries; configured avatar metadata does not establish that its file is usable
unread, pinned, pinnedAt, folded, groupOverride, nestMembersOptional unread information and display preferences for the instance's current user; do not fabricate observed values for absent fields

List Runs​

GET /api/runs​

Runs are ordered by started_at, newest first. Cleared conversation records are excluded by default. Filters apply to all readable records before taking up to limit entries. Multiple filters are combined with AND.

Query parameterTypeDefault and meaning
limitOne decimal positive integer stringDefaults to 50; must convert to a safe integer, with no additional universal count cap
agent_idstringOptional: the Agent that executed the Run
delegated_bystringOptional: the delegating Agent, matching delegation.fromAgentId
parent_run_idstringOptional: the parent delegation Run, matching delegation.parentRunId

This endpoint provides no offset, cursor, or total. Do not apply another endpoint's pagination fields. Empty, negative, fractional, mixed, repeated, or unsafe integer limit values return 400.

Obtain AGENT_ID from the Agent list, then query that Agent's Runs:

AGENT_ID='your-agent-id'

curl --silent --show-error --get \
--header "X-Agent-Service-Token: ${AGENT_SERVICE_TOKEN}" \
--data-urlencode "agent_id=${AGENT_ID}" \
--data-urlencode 'limit=20' \
"${BASE_URL}/api/runs"
{
"runs": [
{
"run_id": "00000000-0000-4000-8000-000000000001",
"user_id": "example-owner",
"agent_id": "your-agent-id",
"started_at": "2026-10-14T01:00:00.000Z",
"status": "idle"
}
]
}

Each runs item contains the metadata described below. This list does not replay every realtime event or associate completion with a particular Webhook request.

Read Run Details​

GET /api/runs/:id​

Use an existing Run ID for :id. There is no request body or additional query parameter. Success returns the Run metadata object directly, without a run or data wrapper.

RUN_ID='replace-with-an-existing-run-id'

curl --silent --show-error \
--header "X-Agent-Service-Token: ${AGENT_SERVICE_TOKEN}" \
"${BASE_URL}/api/runs/${RUN_ID}"
{
"run_id": "00000000-0000-4000-8000-000000000001",
"user_id": "example-owner",
"agent_id": "your-agent-id",
"started_at": "2026-10-14T01:00:00.000Z",
"status": "idle"
}
FieldMeaning
run_id, user_id, agent_idRequired strings identifying the Run, initiating user, and executing Agent
started_atRequired ISO 8601 creation time; a Run can be reused across multiple turns
statusRequired: running, idle, completed, or failed
conversation_id, session_idOptional conversation and realtime execution session identifiers; do not confuse them with one submission's request ID
turn_started_at, completed_at, updatedAtOptional current turn start, Run completion, and latest activity times
failure_reasonFailure reasons include process_restart, timeout, stale, and error
interruption_reason, interrupted_atOptional interruption reason and time; user stops, system suspension, and background timeouts have distinct identifiers
delegationOptional delegation lineage, including fromAgentId and possibly parentRunId, parentClientRequestId, and mode
background, inboundOptional current turn identity, for background processing and a message from another Agent respectively
title, messageCount, archived_at, clearedOptional title, message count, and history lifecycle information
team_id, work_context_id, execution_attachmentOptional execution ownership information; reading these fields grants no resource permissions

Responses may also include optional context, recovery, and working directory metadata. An absent field means that information is not recorded; do not invent completion times, failure reasons, or ownership.

idle means the Run is not currently executing and can await another turn. It does not establish business success; an interrupted Run can also return to idle. completed and failed describe the Run lifecycle. To evaluate a particular submission, associate it with that turn's terminal event and receipt.

Some historical branches can appear in the list while this detail endpoint returns 404. Use the endpoints below when you need runtime state or receipts, and handle their own read results separately.

Read Runtime State​

GET /api/runs/:id/runtime-state​

Returns a persisted Run state snapshot with support for historical branches. :id accepts only letters, digits, underscores, and hyphens. A successful response contains exactly three fields:

curl --silent --show-error \
--header "X-Agent-Service-Token: ${AGENT_SERVICE_TOKEN}" \
"${BASE_URL}/api/runs/${RUN_ID}/runtime-state"
{
"run_id": "00000000-0000-4000-8000-000000000001",
"agent_id": "your-agent-id",
"status": "idle"
}

status accepts only running, idle, completed, and failed. An unreadable or unsupported state returns 404. A stored running value is preserved, but this is still a snapshot. It grants no permission to cancel, rewind, or otherwise modify the Run, and the state can change before a subsequent submission.

Read Execution Receipts​

GET /api/runs/:id/receipt​

Receipts contain turn inputs, outputs, tool calls, and outcomes. The endpoint resolves a trusted user from the instance credential; it accepts no user_id parameter as a substitute for identity checks. A Run belonging to another user returns 404, even if another read endpoint returned its metadata.

Without offset or limit, the response is { "run_id": "...", "receipts": [...] }, with existing receipts in write order. Prefer pagination to bound each read. Providing either pagination parameter enables these rules:

Query parameterDefaultEffective range and handling
offset0One nonnegative decimal integer string; skips from the latest receipt backwards, capped at 10000
limit20One positive decimal integer string, capped at 100

Both parameters must be valid before and after conversion. Empty, fractional, negative, repeated, mixed, and unsafe integer values return 400. Response offset and limit contain the effective values. Receipts within a page remain in write order, so its last item is a newer receipt in that page.

curl --silent --show-error --get \
--header "X-Agent-Service-Token: ${AGENT_SERVICE_TOKEN}" \
--data-urlencode 'offset=0' \
--data-urlencode 'limit=20' \
"${BASE_URL}/api/runs/${RUN_ID}/receipt"
{
"run_id": "00000000-0000-4000-8000-000000000001",
"receipts": [
{
"receipt_id": "example-receipt-id",
"run_id": "00000000-0000-4000-8000-000000000001",
"goal": "Reply to the test message",
"input": "Please say hello.",
"output": "Hello.",
"tool_calls": [],
"outcome": { "status": "success", "auto_completed": true },
"started_at": "2026-10-14T01:00:00.000Z",
"completed_at": "2026-10-14T01:00:01.000Z"
}
],
"total": 1,
"offset": 0,
"limit": 20,
"has_more": false,
"skipped": 0
}
FieldHow to use it
receipt_idStable identifier of one receipt; a Run can have multiple receipts
goal, input, output, tool_callsGoal, input, output, and tool calls; these can contain business data
outcome.statussuccess, partial, or failed, describing that receipt's outcome
outcome.auto_completedWhether completion required no human intervention
started_at, completed_atThat receipt's start and completion times
usage, duration_ms, interruption_reasonOptional usage, duration, and interruption information; absence does not establish zero usage or normal completion
total, has_morePagination count and whether older records remain; absent without pagination parameters
skippedDamaged or oversized records skipped during a paged read, not a business failure count

Historical records can also be skipped during Schema validation. Thus receipts.length can be smaller than the number of records traversed, and total is not the array length. Advance to older pages using response offset + limit, not receipts.length. Stop at the 10000 offset cap to avoid rereading the same page.

Empty receipts, skipped historical entries, or an older last receipt do not independently establish completion of the current turn. Reconcile the target Run, turn timing, and any available turn correlation information. Keep the outcome unknown when evidence is insufficient.

Read Errors​

Endpoint or scopeHTTP status and bodyAction
All endpoints401, error: "unauthorized"Check the instance token and target address
All endpoints403 origin_not_allowed or 503 service_not_readyFollow Errors and Troubleshooting for origin restrictions or startup waiting
Run list and paged receipts400, with error starting Invalid pagination:Use one valid decimal integer per parameter
Run details404, error: "Run not found: ..."Check the Run ID and detail read scope
Runtime state and receipts400, error: "Invalid run ID"Use a safe Run ID returned by the service; do not construct a path
Runtime state404, error: "Run runtime state not found: ..."No supported runtime state is readable; do not assume idle
Receipts401, error: "无法解析用户身份"Ask the administrator to check instance identity configuration
Receipts404, error: "Run not found: ..."Missing, unreadable, or differently owned Run; do not bypass ownership checks
Read failure500Save the redacted response and ask the administrator to inspect service logs; use the actual returned error body

Query parameters do not change execution permissions. Read endpoints can be queried again to update observations. Do not automatically turn a failed read or missing record into a new task submission.

Start and Continue a Conversation​

Submit through HTTP and receive progress and turn termination through Socket.IO. Use an Agent with its model and execution permissions configured. HTTP and Socket.IO must connect to the same instance using an instance token for the same identity.

Run the Node.js Example​

Download the client example and save it as agent-client.mjs. It demonstrates text submission, sequential follow-ups, persistent request information, reconnection checks, and explicit cancellation. Use Node.js 22+ and install the dependency in the separate directory containing the example:

npm init -y
npm install socket.io-client@4.8.4

Set your instance address, existing token, and an Agent ID obtained from the list:

export DESIRECORE_URL='https://agent.example.com'
export DESIRECORE_TOKEN='replace-with-your-existing-instance-token'
export DESIRECORE_AGENT_ID='your-agent-id'

node agent-client.mjs \
--prompt 'Please say hello.' \
--follow-up 'Please reply in another language.' \
--state ./request.json

You can repeat --follow-up. The example attempts the next turn only after observing explicit completion and confirming through admission lookup that the session belongs to the current service process. An initial call does not overwrite an existing state file; use a new --state path for a separate task. The file persists original requests, business text, and correlation information without storing the instance token. Handle it as business data.

The program verifies the handshake, registers event listeners, and connects through Socket.IO. Its path is /socket.io/ and authentication is auth: { token, clientInstanceId }, with the same token as the HTTP X-Agent-Service-Token header. clientInstanceId is a stable 16–128 character identifier containing only letters, digits, ., _, :, and -. Authentication binds the client receiving channel; the example does not send an additional subscription message.

HTTP Submission Fields​

POST /api/query/start accepts JSON. Its top level and options reject undeclared fields. Provide a nonempty prompt or valid mediaRefs. The text example uses these fields:

FieldPurpose and example convention
promptUser text for this turn; the example sends a nonempty string
options.agentIdTarget Agent ID
options.conversationIdConversation scope, saved as a stable value and reused for subsequent requests
clientRequestIdStable ID for one submission; preserve it for recovery or bounded replay, and use a new ID for another turn
userMessageIdStable user message ID for this turn, saved with the request
requestDigestRequest content digest beginning qrd1:, calculated by the example according to the protocol; it is not an access credential
originSocketIdCurrent authenticated socket.id; update it after reconnection rather than reusing an old connection ID

Reliable correlation and recovery need these stable identifiers. See OpenAPI Downloads for complete fields and constraints. Adding undeclared permission objects or user identity fields cannot expand authorization.

An admitted new request returns 202:

{
"ok": true,
"clientRequestId": "00000000-0000-4000-8000-000000000002"
}

A duplicate admission response can also contain an existing sessionId. 202 acknowledges admission; it does not prove that the user message was durably committed, a model executed, or the turn completed. Events such as query:started can arrive before the HTTP response. Register listeners before submitting, and correlate both channels by request ID.

POST /api/query/follow-up continues a known execution session with a different request shape:

FieldPurpose and example convention
sessionIdReusable execution session ID returned by the service
originSocketIdCurrent authenticated Socket.IO connection ID
message.idStable user message ID for this turn
message.role"user"
message.contentTurn text
message.timestampUser message time as a millisecond timestamp
clientRequestIdStable request ID for the new turn
requestDigestThe turn's qrd1: digest calculated and saved by the example

An admitted follow-up returns 202 with ok: true, sessionId, and the corresponding clientRequestId. Duplicate admission can include duplicate. Do not submit the start request's prompt/options object as a follow-up.

Receive Events and Determine Turn Termination​

Socket.IO eventMain fieldsAction
query:startedsessionId, possibly runId, agentId, conversationId, and clientRequestIdSave assigned execution identifiers and associate them with the submission
query:followUpAcceptedsessionId, possibly clientRequestIdAssociate follow-up admission information; it is not completion
query:messagesessionId, message, possibly request and conversation identifiersObserve text, tools, or deliveries; message varies by message type
query:completesessionId, possibly clientRequestId, terminal, and resultCorrelate the request and inspect structured terminal; preserve unknown status without terminal information
query:errorerror, possibly code, request and execution identifiersKeep associated errors; do not attribute an uncorrelated error to another request
activity:run_statusrunId, status, possibly sessionIdUpdate Run observations; this is not a single submission's terminal status

query:complete.terminal.status: completed means the turn ended normally. interrupted means it was interrupted; inspect available reason, partial, and runId information. Evaluate business success using output and receipts as well. A result, an explicit delivery message, or an idle Run cannot replace the turn's terminal status.

Without a matching clientRequestId or structured terminal, the example does not declare that this request succeeded. Its state file retains observed information for reconciliation.

Distinguish Identifiers​

IdentifierScope and lifetime
clientInstanceIdClient receiving channel; reused when recovering the same example state
originSocketIdOne Socket.IO connection; changes on reconnection
clientRequestIdOne start or follow-up submission; unchanged for replay, different for each new request
userMessageId / message.idThis turn's user message, at different field locations in start and follow-up
conversationIdConversation scope, reusable across turns
sessionIdService-assigned execution session; reuse only when the service confirms it remains usable
runIdPersistent execution record, reusable across turns with separate receipts
instanceIdData-space identity from the handshake, used to verify the target instance
serverInstanceIdService process generation from admission lookup; changes on restart and is neither a data-space identity nor a credential

Unknown Admission, Retries, and Reconnection​

After a timeout, lost response, or disconnection, preserve the original request IDs, digest, and dispatch time. Use read-only admission lookup to observe its status before deciding whether bounded replay is allowed. Do not generate a new request ID just to retry.

POST /api/query/client-requests/lookup​

This authenticated, read-only operation does not invoke a model. Its JSON top level and each requests item reject undeclared fields:

{
"agentId": "your-agent-id",
"conversationId": "your-agent-id",
"requests": [
{
"clientRequestId": "00000000-0000-4000-8000-000000000002",
"userMessageId": "00000000-0000-4000-8000-000000000003"
}
]
}

agentId is required and conversationId optional. requests contains 1–100 items, each with a required clientRequestId and optional userMessageId. IDs are nonempty strings of at most 256 characters. Success includes protocolVersion: 1, serverInstanceId, observedAt, autoReplayRetentionMs, tombstoneRetentionMs, and results.

results[].statusMeaning and action
committedCommitted; do not replay. May include committedAt, sessionId, committedServerInstance, and executionWitness; it does not establish completion
reservedReserved; wait for a definite outcome rather than sending another concurrent request
absentNo confirmable record at observation time; consider bounded replay only within the service's protection window, preserving the original IDs and identical request content
unknownCannot be determined reliably; stop automatic replay and keep the outcome unknown while investigating

committedServerInstance is current, previous, or unknown, describing the relationship to the service process generation. executionWitness is user-message, none, or unknown, describing observed execution evidence. Neither committed admission nor generation and evidence fields establish business completion.

The example calculates request age using the response protection windows and server observedAt, without hardcoding a permanent retry period. Even absent does not permit automatic replay outside the window. CLIENT_REQUEST_BODY_MISMATCH indicates a content digest mismatch for the same request ID; stop replay and inspect the saved original request. Treat a new task separately from recovery of the original request.

Resume or Inspect Without Submitting​

Resume a saved request:

node agent-client.mjs --resume ./request.json

The example preserves the original IDs and content and updates only originSocketId after reconnection. It does not replay committed requests, keeps observing reserved requests, and stops automatic replay for unknown or expired requests. Recovery does not replace an unusable original session with a new start request. The URL and handshake instance identity must match the saved target.

Inspect admission and readable execution records without submitting:

node agent-client.mjs --recover ./request.json

This mode establishes no Socket.IO subscription and sends no start or follow-up. With a known runId, it reads runtime state and receipts. With only sessionId, it searches for an exact Run match rather than guessing that the latest Run is this execution. These observations cannot replay all missed events or automatically repeat external actions. The outcome remains unknown when this turn's terminal evidence is missing.

Exit codes are 0 for an observed completed turn, 1 for rejection, failure, or interruption, and 2 for an unknown outcome or read-only recovery mode. --recover still returns 2 after completing its read-only checks; this does not mean the task was resubmitted or confirmed to have failed.

Cancel Explicitly​

node agent-client.mjs --cancel ./request.json

When no terminal outcome is recorded, cancellation sends Socket.IO query:abort with known session, conversation, request, and Agent identifiers. There is no synchronous acknowledgment. Wait for a correlated interrupted terminal in query:complete; without confirmation, preserve an unknown outcome. If a terminal outcome is already recorded, the example reports it without sending cancellation again. --resume, --recover, and --cancel are mutually exclusive and cannot be combined with --prompt or --state. Ctrl+C stops the example client without implicitly cancelling the server task.

Submission and Recovery Errors​

HTTP status or identifierAction
400, invalid submission or lookup fieldsCorrect the corresponding request shape; lookup returns client request lookup body does not match schema
401 / 403Check the instance token, page origin, matching HTTP/Socket identity, and target connection; do not alter markers to bypass authentication
409, busy: true and retryable: trueThe conversation is being cleared; wait for clearing to finish, then retry with the original request ID and content
409 CLIENT_REQUEST_BODY_MISMATCH, retryable: falseThe saved ID and request content differ; stop replay and check the original saved request
503, unavailable connection, request registry, or admission confirmationPreserve the actual retryable and error information and inspect admission first; not every 503 permits direct resubmission
Lost response, disconnection, or no correlated terminalReconcile through read-only checks first; keep unknown status and stop automatic replay if unconfirmed