Capacidades e Versionamento de Protocolo
Visão Geral
GET /capabilities é o endpoint de preflight do daemon. Todo cliente SDK deve lê-lo antes de chamar qualquer outra rota para descobrir qual versão de protocolo o daemon fala, quais tags de recurso estão habilitadas e quais workspace runtimes o daemon aceita. O contrato:
- Há apenas uma versão de protocolo:
v1.SERVE_PROTOCOL_VERSION = 'v1'eSUPPORTED_SERVE_PROTOCOL_VERSIONS = ['v1']. A v1 é aditiva internamente; mudanças que quebram o formato do frame são reservadas para a v2. - Cada tag tem uma versão
since. Daemons v2 futuros podem anunciar tanto tags v1 quanto v2. - Algumas tags são condicionais. As tags listadas em
CONDITIONAL_SERVE_FEATURESsão anunciadas apenas quando o toggle de deployment correspondente está habilitado. A presença da tag significa que o comportamento existe. - Tag de capability = contrato de comportamento. Adicionar um novo comportamento sob uma tag existente pode quebrar silenciosamente clientes que fizeram preflight da tag antiga. Um novo comportamento precisa de uma nova tag.
O registro completo fica em packages/cli/src/serve/capabilities.ts.
Responsabilidades
- Declarar cada recurso que o daemon pode anunciar.
- Filtrar recursos anunciados por versão de protocolo e toggles de deployment.
- Expor
getRegisteredServeFeatures()(todas as chaves, sem filtro),getAdvertisedServeFeatures(version, toggles)(filtrado) egetServeProtocolVersions()(envelope{ current, supported }). - Preservar o invariante “tag presente significa comportamento presente”. O
server.test.tsinclui um teste que garante que toda tag condicional é anunciada quando seu toggle está ativo; adicionar uma tag condicional sem um predicado falha nesse teste.
Arquitetura
Envelope de capacidades
/capabilities retorna:
{
v: 1, // CAPABILITIES_SCHEMA_VERSION
mode: 'http-bridge',
features: ServeFeature[],
workspaceCwd: string,
workspaces?: Array<{ id: string, cwd: string, primary: boolean, trusted: boolean }>,
protocol?: { current: 'v1', supported: ['v1'] },
policy?: { permission: PermissionPolicy },
}workspaceCwd é o caminho canônico do workspace primário (veja 02-serve-runtime.md). Os daemons atuais usam workspaces[] como o catálogo de runtimes registrados; multi_workspace_sessions indica que mais de um runtime está ativo. policy.permission é a política ativa do mediador.
ServeCapabilityDescriptor
interface ServeCapabilityDescriptor {
since: ServeProtocolVersion; // current = 'v1'
modes?: readonly string[]; // lists operation modes when a feature has modes
}Quatro tags v1 usam modes:
mcp_guardrails: { since: 'v1', modes: ['warn', 'enforce'] }- os clientes devem fazer preflight de'enforce'antes de depender do comportamento de recusa.permission_mediation: { since: 'v1', modes: ['first-responder', 'designated', 'consensus', 'local-only'] }- este é o conjunto suportado em tempo de build; a política ativa está empolicy.permission.workspace_voice_transcription: { since: 'v1', modes: ['batch'] }- o caminho de transcrição que o daemon oferece.voice_transcribe: { since: 'v1', modes: ['streaming', 'batch'] }- os dois caminhos de transcrição disponíveis no WebSocket/voice/stream.
Tags condicionais
export const CONDITIONAL_SERVE_FEATURES: ReadonlyMap<
ServeFeature,
(toggles: AdvertiseFeatureToggles) => boolean
> = new Map([
['require_auth', (t) => t.requireAuth === true],
['mcp_workspace_pool', (t) => t.mcpPoolActive === true],
['mcp_pool_restart', (t) => t.mcpPoolActive === true],
['allow_origin', (t) => t.allowOriginActive === true],
[
'prompt_absolute_deadline',
(t) => typeof t.promptDeadlineMs === 'number' && t.promptDeadlineMs > 0,
],
[
'writer_idle_timeout',
(t) =>
typeof t.writerIdleTimeoutMs === 'number' && t.writerIdleTimeoutMs > 0,
],
['workspace_settings', (t) => t.persistSettingAvailable === true],
['user_language_sync', (t) => t.persistSettingAvailable === true],
['workspace_voice', (t) => t.persistSettingAvailable === true],
[
'workspace_voice_transcription',
(t) => t.voiceTranscriptionAvailable === true,
],
['session_shell_command', (t) => t.sessionShellCommandEnabled === true],
[
'multi_workspace_session_rewind',
(t) => t.multiWorkspaceSessionsEnabled === true,
],
[
'multi_workspace_session_shell',
(t) =>
t.multiWorkspaceSessionsEnabled === true &&
t.sessionShellCommandEnabled === true,
],
['rate_limit', (t) => t.rateLimit === true],
['workspace_reload', (t) => t.reloadAvailable === true],
['voice_transcribe', (t) => t.voiceWsAvailable !== false],
]);O Map armazena a associação e o predicado juntos. Adicionar uma nova tag condicional requer duas mudanças coordenadas:
- Registrar a tag e sua versão
sinceemSERVE_CAPABILITY_REGISTRY. - Adicionar seu predicado a
CONDITIONAL_SERVE_FEATURES.
As tags base não estão presentes no Map e são anunciadas incondicionalmente. Isso é representado intencionalmente pela ausência, em vez de por um Set separado.
Tags v1 agrupadas por domínio
Fundação: health, daemon_status, capabilities.
Sessões: session_create, session_id_override, session_scope_override, session_load, session_resume, unstable_session_resume, session_list, session_info, session_prompt, session_mid_turn_message_mutation, session_cancel, session_events, session_set_model, session_close, session_metadata, session_archive, session_storage_conflict_repair, session_export, session_transcript, session_context, session_context_usage, session_supported_commands, session_tasks, session_monitor_tool_correlation, session_stats, session_lsp, session_resources, session_status, session_approval_mode_control, session_recap, session_btw, session_shell_command (condicional), session_language, user_language_sync (condicional), session_rewind, session_hooks, session_branch.
Streaming: slow_client_warning, typed_event_schema.
Identidade e heartbeat: client_identity, client_heartbeat.
Permissões: session_permission_vote, permission_vote, permission_mediation (modes: ['first-responder', 'designated', 'consensus', 'local-only']).
Snapshots read-only do workspace: workspace_mcp, workspace_skills, workspace_providers, workspace_acp_status, workspace_env, workspace_preflight, workspace_hooks, workspace_extensions.
Gerenciamento de extensões: extension_management_v2 adiciona o contrato global de catálogo/mutação/operação /extensions/* e a projeção de ativação do workspace. É separado da superfície de compatibilidade publicada workspace_extensions e de workspace_qualified_rest_core.
Instalação local de Extensões: extension_local_path_install permite um caminho absoluto no host do daemon no campo source existente de ambas as rotas de instalação de Extensões. É separado de extension_management_v2 porque a rota de compatibilidade do workspace primário também o suporta, e clientes não devem enviar caminhos locais para daemons mais antigos.
Ativação em lote de Extensões V2: extension_batch_activation_v2 adiciona lotes enfileirados de ativação padrão global e substituição de workspace selecionado ao extension_management_v2. Os clientes devem fazer pre-flight dela independentemente porque daemons V2 mais antigos expõem apenas rotas de ativação singular.
Atualização explícita de ativação de Extensão: extension_activation_explicit_refresh significa que operações de ativação singular e em lote terminam no commit de política durável sem atualizar diretamente as sessões ativas. Clientes que precisam de aplicação imediata devem aguardar o sucesso da ativação e submeter a operação de atualização de runtime do workspace para cada workspace cujas sessões devem aplicar a mudança imediatamente; um lote padrão global altera a ativação padrão que cada workspace herda, a menos que esse workspace tenha uma substituição exata para o nome (ou corresponda a uma regra de caminho legada), e não há uma única atualização que cubra cada runtime, então workspaces que o chamador não atualizar convergem apenas na próxima passagem do reconciliador de geração a cada 30 segundos. Daemons sem essa tag já incluem atualização na operação de ativação, então os chamadores não devem submeter uma atualização de compatibilidade lá.
Leituras de sessão qualificadas por workspace: workspace_persisted_transcript, workspace_session_export, workspace_archived_session_export, workspace_session_live_state. As tags de exportação ativa e arquivada são independentes entre si e de session_export e workspace_qualified_rest_core, então os clientes devem fazer pre-flight do estado exato de armazenamento que pretendem exportar. A paginação de transcrição persistida permite um secundário não confiável sob sua política de leitura limitada; ambos os caminhos de exportação completa permanecem apenas para confiáveis. workspace_session_live_state também é independente de workspace_qualified_rest_core e é apenas para confiáveis: serve o snapshot de sessão ao vivo em memória e a versão do catálogo do runtime selecionado e não estende a política de leitura persistida do secundário não confiável ao estado ao vivo da bridge.
Mutação do workspace (Wave 4+): workspace_memory, workspace_agents, workspace_agent_generate, workspace_acp_preheat, workspace_tool_toggle, workspace_skill_settings_toggle, workspace_skill_settings_batch_toggle, workspace_settings (condicional), workspace_permissions, workspace_init, workspace_github_setup, workspace_trust, workspace_mcp_restart, workspace_mcp_manage, workspace_file_read, workspace_file_bytes, workspace_file_read_cursor, workspace_file_write, workspace_file_upload, workspace_reload (condicional). As duas tags de configuração de Skill substituem as tags aposentadas e validadas pelo catálogo workspace_skill_toggle e workspace_skill_batch_toggle.
Guardrails do MCP: mcp_guardrails (modes: ['warn', 'enforce']), mcp_guardrail_events, mcp_server_runtime_mutation, mcp_workspace_pool (condicional), mcp_pool_restart (condicional).
Controle de prompt: prompt_absolute_deadline (condicional), writer_idle_timeout (condicional), non_blocking_prompt.
Autenticação: auth_provider_install, auth_device_flow, require_auth (condicional), allow_origin (condicional).
Voz: workspace_voice (condicional), workspace_voice_transcription (condicional, modes: ['batch']), voice_transcribe (condicional, modes: ['streaming', 'batch']).
Limite de taxa: rate_limit (condicional).
Roteamento de sessão multi-workspace: multi_workspace_sessions (condicional),
multi_workspace_session_rewind (condicional) e
multi_workspace_session_shell (condicional). Um cliente pode usar rewind
para uma sessão primária com session_rewind; uma sessão secundária ativa
adicionalmente requer multi_workspace_session_rewind. Shell usa o pareamento
equivalente session_shell_command mais multi_workspace_session_shell para
uma sessão secundária. Clientes nativos ACP continuam usando os _qwen.methods
retornados pelo initialize; nenhum método vendor de rewind ACP é anunciado.
Tags em negrito têm modes ou são condicionais.
Fluxo
Lado do daemon: montar o envelope
Lado do cliente: preflight de recursos
Estado e ciclo de vida
CAPABILITIES_SCHEMA_VERSIONé a versão do formato do envelope na rede, atualmente1. Incremente apenas em caso de quebra no envelope.SERVE_PROTOCOL_VERSION = 'v1'é a versão de protocolo-recurso. Adicionar recursos dentro da v1 é aditivo; clientes antigos não veem o novo comportamento a menos que façam preflight da nova tag. Comportamentos corrigidos podem substituir uma capability dentro da v1: a tag de substituição sobrescreve a tag antiga, a tag antiga deixa de ser anunciada, e os clientes devem fazer preflight da substituição. Remover um recurso sem substituição é uma quebra na v2.EVENT_SCHEMA_VERSION = 1é o campovdo frame SSE (veja09-event-schema.md). É um eixo de versão independente; incrementar o schema de eventos não implica incrementar a versão do protocolo, e vice-versa.session_resumeé a capability estável do daemon paraPOST /session/:id/resume.unstable_session_resumecontinua sendo anunciado como um alias depreciado porque o método ACP subjacente ainda se chamaconnection.unstable_resumeSession; novos clientes devem detectar o recursosession_resume.
Dependências
- Lido por
packages/cli/src/serve/server.tsao construir respostas de/capabilities. - A entrada de toggles vem de
runQwenServe/createServeApp, incluindo autenticação, MCP, origin, prompt, configurações, shell, rate-limit, reload e estado dinâmico de contagem de workspace runtime. - A política
permissionativa no envelope vem deBridgeOptions.permissionPolicy, que por sua vez lêpolicy.permissionStrategyemsettings.json.
Configuração
| Origem | Opção | Efeito nas capacidades |
|---|---|---|
| Flag da CLI | --require-auth | Anuncia require_auth. |
| Env | QWEN_SERVE_NO_MCP_POOL=1 | Para de anunciar mcp_workspace_pool e mcp_pool_restart; eventos do MCP não estampam mais scope: 'workspace'. |
| Flag da CLI | --mcp-client-budget=N, --mcp-budget-mode={off,warn,enforce} | Não altera o conjunto de tags (mcp_guardrails é sempre anunciado), mas altera a reserva por servidor e o comportamento de recusa. |
| Flag da CLI / env | --rate-limit / QWEN_SERVE_RATE_LIMIT=1 | Anuncia rate_limit. |
| Opção embutida | persistSettingAvailable | Anuncia workspace_settings, user_language_sync e workspace_voice. |
| Opção embutida | voiceTranscriptionAvailable | Anuncia workspace_voice_transcription. |
| Flag da CLI / opção embutida | --enable-session-shell / sessionShellCommandEnabled | Anuncia session_shell_command. |
| Estado de runtime | Mais de um workspace runtime registrado | Anuncia multi_workspace_sessions e multi_workspace_session_rewind; também anuncia multi_workspace_session_shell quando o shell de sessão está efetivamente habilitado. |
| Opção embutida | reloadAvailable | Anuncia workspace_reload. |
| Opção embutida | voiceWsAvailable | Anuncia voice_transcribe. |
settings.json | policy.permissionStrategy | Define policy.permission no envelope. |
Ressalvas e limitações conhecidas
--require-authoculta o preflight. Com--require-auth, todas as rotas, incluindo/capabilities, exigem bearer auth. Um cliente não autenticado não pode fazer preflight decaps.features.require_auth; o corpo da resposta 401 é a superfície de descoberta. A tagrequire_authé uma confirmação autenticada para UIs de auditoria de deployments com segurança reforçada.- A presença da tag significa que o comportamento existe. Se um futuro contribuidor adicionar um comportamento sob uma tag existente sem incrementar
since, clientes que fizeram preflight da tag antiga podem receber silenciosamente o novo comportamento. A convenção é: novo comportamento recebe uma nova tag. - Tags
unstable_*podem mudar de formato entre versões sem um incremento de protocolo. Fixe uma versão do SDK ao depender delas. - O catálogo de rotas fica em
../qwen-serve-protocol.md; esta página intencionalmente não o duplica.
Referências
packages/cli/src/serve/capabilities.tspackages/cli/src/serve/types.ts(ServeOptions,CapabilitiesEnvelope)packages/cli/src/serve/server.ts(montagem do envelope)packages/acp-bridge/src/eventBus.ts(EVENT_SCHEMA_VERSION)- Referência de wire:
../qwen-serve-protocol.md - Guardrails de autenticação e de deployment:
12-auth-security.md