mirror of
https://github.com/QwenLM/qwen-code.git
synced 2026-11-01 04:02:35 +00:00
* feat(web-shell): prepare updates and restart from sidebar * test(serve): include daemon update in capability contracts * test: complete update contracts and isolate shell output fixtures * fix(web-shell): preserve task URLs and check update launchers * fix(serve): support older Node declarations in update checks
150 lines
28 KiB
Markdown
150 lines
28 KiB
Markdown
# Daemon REST API Reference
|
|
|
|
This is the public REST/SSE interface for integrations that run
|
|
`qwen serve --no-web` and provide their own UI. Start with the
|
|
[integration guide](./rest-api-integration.md), then use this page for endpoint
|
|
discovery and the [HTTP protocol reference](./qwen-serve-protocol.md) for
|
|
detailed lifecycle semantics.
|
|
|
|
## OpenAPI
|
|
|
|
The curated 25-operation contract is available as
|
|
[OpenAPI 3.1 JSON](https://raw.githubusercontent.com/QwenLM/qwen-code/main/docs/developers/daemon-rest-api.openapi.json).
|
|
Import that URL into an OpenAPI-compatible renderer, client generator, or
|
|
validation tool. The checked-in JSON is the portable interface contract for the
|
|
operations indexed below and is validated against the guide, protocol headings,
|
|
and registered routes in CI.
|
|
|
|
This index covers a curated core subset of the daemon's REST surface, not all
|
|
of it.
|
|
Outside it are the first-party Web Shell routes, conditional internal surfaces,
|
|
and other public but non-core routes: file mutation, workspace registration,
|
|
session organization and generation, and workspace MCP, skills, and providers
|
|
among them. Those surfaces are advertised by their own capability tags; the
|
|
[HTTP protocol reference](./qwen-serve-protocol.md) documents the session,
|
|
workspace-status, and file surfaces, and MCP server management, auth providers,
|
|
and device-flow sign-in are covered by the
|
|
[daemon auth and security notes](./daemon/12-auth-security.md). They are outside
|
|
this contract, not deprecated.
|
|
|
|
## Reading the index
|
|
|
|
- **Capability** is the feature tag to check in `GET /capabilities`. An
|
|
em dash means the operation has no dedicated feature tag; clients that need
|
|
to support older daemon builds should handle `404`.
|
|
- **Scope** says which runtime owns the operation. `process-global` reads
|
|
daemon-wide state, `selected-runtime` uses the request's workspace selection,
|
|
`persisted-workspace` resolves persisted session storage, `live-session-owner`
|
|
routes by the live session, and `legacy-primary` always targets the daemon's
|
|
primary workspace. `GET /session/:id/export` is primary-pinned: it resolves
|
|
only managed internal runtimes before falling back to the primary workspace.
|
|
- All operations in this index are **stable** in the v1 REST contract. The
|
|
deprecated `unstable_session_resume` capability name is only an alias; use
|
|
`session_resume` for the stable resume route.
|
|
|
|
Creation with `startupConfig: { modelServiceId, reasoningEffort? }` additionally requires `session_startup_config`. Only the model is required; omission of reasoning does not set a default. Successful preparation returns `modelApplied: true` and `startupConfigApplied`; malformed input returns `400 invalid_startup_config`, while rejected selection returns `422 startup_config_rejected`. See the [startup negotiation contract](./qwen-serve-protocol.md#capabilities) for ordinary and standalone behavior.
|
|
|
|
## Discovery
|
|
|
|
| Operation | Capability | Scope | TypeScript SDK |
|
|
| ---------------------------------------------------------------- | -------------- | ---------------- | --------------------------- |
|
|
| [`GET /health`](./qwen-serve-protocol.md#get-health) | `health` | `process-global` | `DaemonClient.health` |
|
|
| [`GET /capabilities`](./qwen-serve-protocol.md#get-capabilities) | `capabilities` | `process-global` | `DaemonClient.capabilities` |
|
|
|
|
## Session lifecycle
|
|
|
|
| Operation | Capability | Scope | TypeScript SDK |
|
|
| --------------------------------------------------------------------------------- | ------------------- | -------------------- | ------------------------------------ |
|
|
| [`POST /session`](./qwen-serve-protocol.md#post-session) | `session_create` | `selected-runtime` | `DaemonClient.createOrAttachSession` |
|
|
| [`POST /session/:id/load`](./qwen-serve-protocol.md#post-sessionidload) | `session_load` | `selected-runtime` | `DaemonClient.loadSession` |
|
|
| [`POST /session/:id/resume`](./qwen-serve-protocol.md#post-sessionidresume) | `session_resume` | `selected-runtime` | `DaemonClient.resumeSession` |
|
|
| [`POST /session/:id/heartbeat`](./qwen-serve-protocol.md#post-sessionidheartbeat) | `client_heartbeat` | `live-session-owner` | `DaemonClient.heartbeat` |
|
|
| [`PATCH /session/:id/metadata`](./qwen-serve-protocol.md#patch-sessionidmetadata) | `session_metadata` | `live-session-owner` | `DaemonClient.updateSessionMetadata` |
|
|
| [`POST /session/:id/model`](./qwen-serve-protocol.md#post-sessionidmodel) | `session_set_model` | `live-session-owner` | `DaemonClient.setSessionModel` |
|
|
| [`DELETE /session/:id`](./qwen-serve-protocol.md#delete-sessionid) | `session_close` | `live-session-owner` | `DaemonClient.closeSession` |
|
|
|
|
## Prompts and events
|
|
|
|
| Operation | Capability | Scope | TypeScript SDK |
|
|
| ------------------------------------------------------------------------------------------- | -------------------- | --------------------- | --------------------------------------- |
|
|
| [`GET /session/:id/status`](./qwen-serve-protocol.md#get-sessionidstatus) | `session_status` | `live-session-owner` | `DaemonClient.sessionStatus` |
|
|
| [`POST /session/:id/prompt`](./qwen-serve-protocol.md#post-sessionidprompt) | `session_prompt` | `live-session-owner` | `DaemonClient.promptNonBlocking` |
|
|
| [`POST /session/:id/cancel`](./qwen-serve-protocol.md#post-sessionidcancel) | `session_cancel` | `live-session-owner` | `DaemonClient.cancel` |
|
|
| [`GET /session/:id/events`](./qwen-serve-protocol.md#get-sessionidevents-sse) | `session_events` | `live-session-owner` | `DaemonClient.subscribeEvents` |
|
|
| [`GET /session/:id/transcript`](./qwen-serve-protocol.md#get-sessionidtranscript) | `session_transcript` | `persisted-workspace` | `DaemonClient.getSessionTranscriptPage` |
|
|
| [`GET /session/:id/context`](./qwen-serve-protocol.md#get-sessionidcontext) | `session_context` | `live-session-owner` | `DaemonClient.sessionContext` |
|
|
| [`GET /session/:id/export`](./qwen-serve-protocol.md#get-sessionidexport) | `session_export` | `legacy-primary` | `DaemonClient.exportSession` |
|
|
| [`GET /session/:id/pending-prompts`](./qwen-serve-protocol.md#get-sessionidpending-prompts) | — | `live-session-owner` | `DaemonClient.getPendingPrompts` |
|
|
|
|
`POST /session/:id/prompt` returns `202` when the prompt enters the queue, not
|
|
when the Agent finishes. Subscribe first, then correlate `turn_complete` or
|
|
`turn_error` by `promptId`.
|
|
|
|
## Permissions
|
|
|
|
| Operation | Capability | Scope | TypeScript SDK |
|
|
| ------------------------------------------------------------------------------------------------------- | ------------------------- | -------------------- | ----------------------------------------- |
|
|
| [`POST /session/:id/permission/:requestId`](./qwen-serve-protocol.md#post-sessionidpermissionrequestid) | `session_permission_vote` | `live-session-owner` | `DaemonClient.respondToSessionPermission` |
|
|
| [`POST /permission/:requestId`](./qwen-serve-protocol.md#post-permissionrequestid) | `permission_vote` | `legacy-primary` | `DaemonClient.respondToPermission` |
|
|
|
|
New multi-workspace integrations should always use the session-scoped route.
|
|
The legacy route can return the same `404` for a request owned by another
|
|
runtime as it does for an already-resolved vote.
|
|
|
|
## Read-only workspace context
|
|
|
|
| Operation | Capability | Scope | TypeScript SDK |
|
|
| --------------------------------------------------------------------- | ---------------------- | ---------------- | ------------------------------------- |
|
|
| [`GET /workspace/tools`](./qwen-serve-protocol.md#get-workspacetools) | — | `legacy-primary` | `DaemonClient.workspaceTools` |
|
|
| [`GET /file`](./qwen-serve-protocol.md#get-file) | `workspace_file_read` | `legacy-primary` | `DaemonClient.readWorkspaceFile` |
|
|
| [`GET /file/bytes`](./qwen-serve-protocol.md#get-filebytes) | `workspace_file_bytes` | `legacy-primary` | `DaemonClient.readWorkspaceFileBytes` |
|
|
| [`GET /stat`](./qwen-serve-protocol.md#get-stat) | `workspace_file_read` | `legacy-primary` | `DaemonClient.fileStat` |
|
|
| [`GET /list`](./qwen-serve-protocol.md#get-list) | `workspace_file_read` | `legacy-primary` | `DaemonClient.dirList` |
|
|
| [`GET /glob`](./qwen-serve-protocol.md#get-glob) | `workspace_file_read` | `legacy-primary` | `DaemonClient.glob` |
|
|
|
|
These singular routes target the primary workspace. Integrations that expose
|
|
multiple registered workspaces should use the workspace-qualified counterparts
|
|
documented in the full protocol and preflight `workspace_qualified_rest_core`.
|
|
|
|
## Additional documented APIs
|
|
|
|
The 25 operations above are the stable OpenAPI integration contract. The
|
|
following operations complete the index of HTTP routes with dedicated protocol
|
|
sections. They are documented v1 surfaces, but they are outside that compact
|
|
OpenAPI contract because they are conditional, administrative, or primarily
|
|
support first-party clients. Preflight every listed capability and treat a
|
|
missing capability as an unavailable route. A grouped row can contain several
|
|
operations when they share ownership and an SDK family.
|
|
|
|
| Area | Operations | Capability and scope | TypeScript SDK |
|
|
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
| Operator state | [`GET /daemon/status`](./qwen-serve-protocol.md#get-daemonstatus) · [`GET /brand`](./qwen-serve-protocol.md#get-brand) · [`GET /daemon/update`](./qwen-serve-protocol.md#get-daemonupdate-post-daemonupdateprepare-and-post-daemonupdaterestart) · [`POST /daemon/update/prepare`](./qwen-serve-protocol.md#get-daemonupdate-post-daemonupdateprepare-and-post-daemonupdaterestart) · [`POST /daemon/update/restart`](./qwen-serve-protocol.md#get-daemonupdate-post-daemonupdateprepare-and-post-daemonupdaterestart) | `daemon_status`, `web_shell_brand`, `daemon_update`; process-global | `DaemonClient.daemonStatus`, `DaemonClient.brand`, `DaemonClient.daemonUpdateStatus`, `DaemonClient.prepareDaemonUpdate`, `DaemonClient.restartDaemonForUpdate` |
|
|
| Workspace registration | [`POST /workspaces`](./qwen-serve-protocol.md#post-workspaces) · [`PATCH /workspaces/:workspace`](./qwen-serve-protocol.md#patch-workspacesworkspace) · [`DELETE /workspaces/:workspace`](./qwen-serve-protocol.md#delete-workspacesworkspace) · [`GET /workspace-registrations`](./qwen-serve-protocol.md#get-workspace-registrations) · [`DELETE /workspace-registrations/:id`](./qwen-serve-protocol.md#delete-workspace-registrationsid) | `dynamic_workspace_registration`, `persistent_workspace_registration`, `workspace_display_name`, `workspace_runtime_removal`; process-global or selected-runtime | `DaemonClient.addWorkspace`, `DaemonClient.updateWorkspace`, `WorkspaceDaemonClient.remove`; registration-store routes use raw REST |
|
|
| Workspace runtime status | [`GET /workspace/mcp`](./qwen-serve-protocol.md#get-workspacemcp) · [`GET /workspace/skills`](./qwen-serve-protocol.md#get-workspaceskills) · [`GET /workspace/providers`](./qwen-serve-protocol.md#get-workspaceproviders) · [`GET /workspace/env`](./qwen-serve-protocol.md#get-workspaceenv) · [`GET /workspace/preflight`](./qwen-serve-protocol.md#get-workspacepreflight) | `workspace_mcp`, `workspace_skills`, `workspace_providers`, `workspace_env`, `workspace_preflight`; legacy-primary | `DaemonClient.workspaceMcp`, `workspaceSkills`, `workspaceProviders`, `workspaceEnv`, `workspacePreflight` |
|
|
| File mutation | [`POST /file/write`](./qwen-serve-protocol.md#post-filewrite) · [`POST /file/edit`](./qwen-serve-protocol.md#post-fileedit) | `workspace_file_write`; legacy-primary | `DaemonClient.writeWorkspaceFile`, `DaemonClient.editWorkspaceFile` |
|
|
| Session inspection and tasks | [`GET /session/:id/supported-commands`](./qwen-serve-protocol.md#get-sessionidsupported-commands) · [`GET /session/:id/tasks`](./qwen-serve-protocol.md#get-sessionidtasks) · [`POST /session/:id/tasks/:taskId/workflow-action`](./qwen-serve-protocol.md#post-sessionidtaskstaskidworkflow-action) · [`GET /session/:id/lsp`](./qwen-serve-protocol.md#get-sessionidlsp) · [`GET /session/:id/resources`](./qwen-serve-protocol.md#get-sessionidresources) | `session_supported_commands`, `session_tasks`, `session_lsp`, `session_resources`; live-session-owner | `DaemonClient.sessionSupportedCommands`, `sessionTasks`, `sessionWorkflowTaskAction`, `sessionLspStatus`, `sessionResources` |
|
|
| Workspace-qualified history | [`GET /workspaces/:workspace/session/:id/transcript`](./qwen-serve-protocol.md#get-workspacesworkspacesessionidtranscript) · [`GET /workspaces/:workspace/session/:id/export`](./qwen-serve-protocol.md#get-workspacesworkspacesessionidexport) · [`GET /workspaces/:workspace/session/:id/archive/export`](./qwen-serve-protocol.md#get-workspacesworkspacesessionidarchiveexport) | `workspace_persisted_transcript`, `workspace_session_export`, `workspace_archived_session_export`; persisted-workspace | `WorkspaceDaemonClient.getSessionTranscriptPage`, `exportSession`, `exportArchivedSession` |
|
|
| Worktree recovery | [`POST /session/:id/worktree-reset`](./qwen-serve-protocol.md#post-sessionidworktree-reset) | `session_worktree_reset_v1`; live-session-owner | `DaemonClient.resetWorktreeSession` |
|
|
| Persisted session catalog | [`POST /sessions/catalog`](./qwen-serve-protocol.md#post-sessionscatalog) · [`GET /workspace/:id/session-info`](./qwen-serve-protocol.md#get-workspaceidsession-info-and-get-workspacesworkspacesession-info) · [`GET /workspaces/:workspace/session-info`](./qwen-serve-protocol.md#get-workspaceidsession-info-and-get-workspacesworkspacesession-info) · [`GET /workspace/:id/sessions`](./qwen-serve-protocol.md#get-workspaceidsessions-and-get-workspacesworkspacesessions) · [`GET /workspaces/:workspace/sessions`](./qwen-serve-protocol.md#get-workspaceidsessions-and-get-workspacesworkspacesessions) · [`GET /workspaces/:workspace/sessions/live-state`](./qwen-serve-protocol.md#get-workspacesworkspacesessionslive-state) | `session_info`, `session_list`, `workspace_session_live_state`; persisted-workspace; `session_catalog_batch`; persisted-workspace per member | `DaemonClient.getStandaloneSession`, `listWorkspaceSessions`, `listSessionsCatalog`, `getWorkspaceSessionLiveState` |
|
|
| Session organization | [`GET /workspace/:id/session-groups`](./qwen-serve-protocol.md#get-workspaceidsession-groups) · [`POST /workspace/:id/session-groups`](./qwen-serve-protocol.md#post-workspaceidsession-groups) · [`PATCH /workspace/:id/session-groups/:groupId`](./qwen-serve-protocol.md#patch-workspaceidsession-groupsgroupid) · [`DELETE /workspace/:id/session-groups/:groupId`](./qwen-serve-protocol.md#delete-workspaceidsession-groupsgroupid) · [`PATCH /session/:id/organization`](./qwen-serve-protocol.md#patch-sessionidorganization-and-patch-workspacesworkspacesessionidorganization) · [`PATCH /workspaces/:workspace/session/:id/organization`](./qwen-serve-protocol.md#patch-sessionidorganization-and-patch-workspacesworkspacesessionidorganization) | `session_organization`; legacy-primary or persisted-workspace | `DaemonClient.listSessionGroups`, `createSessionGroup`, `updateSessionGroup`, `deleteSessionGroup`, `updateSessionOrganization`; `WorkspaceDaemonClient.updateSessionOrganization` |
|
|
| Bulk persisted-session changes | [`POST /sessions/delete`](./qwen-serve-protocol.md#post-sessionsdelete) · [`POST /sessions/archive`](./qwen-serve-protocol.md#post-sessionsarchive) · [`POST /sessions/unarchive`](./qwen-serve-protocol.md#post-sessionsunarchive) | `session_archive`; legacy-primary | `DaemonClient.deleteSessionsData`, `archiveSessionsData`, `unarchiveSessionsData` |
|
|
| Optional session controls | [`POST /session/:id/recap`](./qwen-serve-protocol.md#post-sessionidrecap) · [`POST /session/:id/generate`](./qwen-serve-protocol.md#post-sessionidgenerate) · [`POST /session/:id/approval-mode`](./qwen-serve-protocol.md#post-sessionidapproval-mode) | `session_recap`, `session_generation`, `session_approval_mode_control`; live-session-owner | `DaemonClient.recapSession`, raw REST for generation, `DaemonClient.setSessionApprovalMode` |
|
|
| Workspace configuration | [`POST /workspace/tools/:name/enable`](./qwen-serve-protocol.md#post-workspacetoolsnameenable) · [`POST /workspace/skills/:name/enable`](./qwen-serve-protocol.md#post-workspaceskillsnameenable) · [`POST /workspace/skills/enable`](./qwen-serve-protocol.md#post-workspaceskillsenable) · [`POST /workspace/init`](./qwen-serve-protocol.md#post-workspaceinit) · [`POST /workspace/mcp/reload`](./qwen-serve-protocol.md#post-workspacemcpreload) · [`POST /workspace/mcp/:server/restart`](./qwen-serve-protocol.md#post-workspacemcpserverrestart) · [`POST /language`](./qwen-serve-protocol.md#post-language) | `workspace_tool_toggle`, `workspace_skill_settings_toggle`, `workspace_skill_settings_batch_toggle`, `workspace_init`, `workspace_mcp_manage`, `workspace_mcp_restart`, `user_language_sync`; legacy-primary or process-global | `DaemonClient.setWorkspaceToolEnabled`, `setWorkspaceSkillEnabled`, `setWorkspaceSkillsEnabled`, `initWorkspace`, `reloadWorkspaceMcp`, `restartMcpServer`, `setUserLanguage` |
|
|
| Device-flow authentication | [`POST /workspace/auth/device-flow`](./qwen-serve-protocol.md#post-workspaceauthdevice-flow) · [`GET /workspace/auth/device-flow/:id`](./qwen-serve-protocol.md#get-workspaceauthdevice-flowid) · [`DELETE /workspace/auth/device-flow/:id`](./qwen-serve-protocol.md#delete-workspaceauthdevice-flowid) · [`GET /workspace/auth/status`](./qwen-serve-protocol.md#get-workspaceauthstatus) | `auth_device_flow`; legacy-primary | `DaemonClient.startDeviceFlow`, `getDeviceFlow`, `cancelDeviceFlow`, `getAuthStatus` |
|
|
|
|
Routes without a dedicated protocol section are intentionally absent from this
|
|
index. They may be first-party Web Shell plumbing or conditional implementation
|
|
surfaces and are not promoted to an integration contract by omission.
|
|
|
|
## Common protocol rules
|
|
|
|
- Authenticate normal routes with `Authorization: Bearer <token>`. A default
|
|
loopback `/health` probe may be exempt; non-loopback binds are not.
|
|
- Send `X-Qwen-Client-Id` when a create/load response supplied one. It is an
|
|
attachment and attribution identifier, not an end-user security principal.
|
|
- Treat error bodies as additive. Branch primarily on HTTP status and the
|
|
stable `code` or `errorKind` when present.
|
|
- Preserve SSE response headers and disable proxy buffering. Resume with both
|
|
`Last-Event-ID` and `X-Qwen-Event-Epoch` when the daemon supplied an epoch.
|
|
- A workspace trust boundary is not tenant isolation. Run separate daemons when
|
|
security principals or process-level failure boundaries must be independent.
|