RPC and API
Modo de código
O modo de código é um recurso experimental e opcional do runtime de agentes do OpenClaw. Quando
ativado, o modelo deixa de ver o esquema de todas as ferramentas habilitadas; em vez disso, ele vê
exec, wait e qualquer ferramenta exclusivamente direta cujo resultado estruturado não possa atravessar
a ponte do guest, que aceita apenas JSON. O modelo escreve um pequeno programa JavaScript ou TypeScript
que pesquisa, descreve e chama o catálogo oculto de ferramentas.
Esta página documenta o modo de código do OpenClaw, não o Codex Code Mode. Os dois recursos
compartilham um nome e os mesmos nomes de ferramentas de controle (exec, wait), mas são
implementações separadas:
- O Codex Code Mode é executado dentro do ambiente de programação do Codex. Sua ferramenta
execé uma ferramenta de gramática livre: o modelo escreve código-fonte JavaScript bruto (opcionalmente prefixado por uma linha de pragma// @exec: {...}para opções de execução), executado em um runtime Deno/V8. - O modo de código do OpenClaw é executado no runtime genérico de agentes do OpenClaw e fica
desativado, a menos que
tools.codeMode.enabled: trueesteja configurado. Sua ferramentaexecrecebe um payload JSON{ code, language }, executado em um worker QuickJS-WASI.
Ambas são superfícies de execução de JavaScript, não superfícies de comandos do shell. Trate-as
como recursos independentes, implementados de maneiras diferentes, que por acaso expõem
ferramentas exec/wait com nomes idênticos.
O que ele faz
- A lista de ferramentas visível ao modelo passa a ser
exec,waite qualquer ferramenta exclusivamente direta, comocomputer, cujo resultado de imagem não possa atravessar a ponte do guest. execavalia JavaScript ou TypeScript gerado pelo modelo em uma thread de worker QuickJS-WASI isolada.- Todas as ferramentas habilitadas elegíveis para o catálogo (núcleo do OpenClaw, Plugin, MCP, cliente) são ocultadas do
prompt do modelo e expostas dentro do programa guest por meio de
ALL_TOOLSetools. - O código guest pesquisa o catálogo oculto, descreve o esquema de uma ferramenta e chama uma ferramenta pelo mesmo caminho de execução usado em turnos normais do agente (políticas, aprovações, hooks e telemetria continuam sendo aplicados).
- As ferramentas MCP são agrupadas no namespace
MCP; no modo de código, essa é a única maneira compatível de chamá-las. waitretoma uma execução suspensa do modo de código quando chamadas de ferramentas aninhadas ainda estão pendentes.
O modo de código altera apenas a superfície de orquestração voltada ao modelo. Ele não substitui ferramentas, ferramentas de Plugin, ferramentas MCP, autenticação, política de aprovação, comportamento do canal ou seleção do modelo.
Por que usá-lo
- Superfície de prompt menor: os provedores recebem duas ferramentas de controle e apenas as poucas ferramentas diretas necessárias, em vez de dezenas ou centenas de esquemas completos de ferramentas.
- Melhor orquestração: o modelo pode usar loops, junções, pequenas transformações, lógica condicional e chamadas paralelas de ferramentas aninhadas dentro de uma única célula de código.
- Neutro em relação ao provedor: funciona com ferramentas do OpenClaw, de Plugins, MCP e de clientes sem depender da execução de código nativa do provedor.
- Falha de forma fechada: se o modo de código estiver ativado, mas o runtime QuickJS-WASI estiver indisponível, a execução falha em vez de recorrer silenciosamente à exposição direta ampla de ferramentas.
É mais útil para agentes com um grande catálogo de ferramentas habilitadas ou para fluxos de trabalho nos quais o modelo precisa pesquisar, combinar e chamar várias ferramentas antes de responder.
Ativá-lo
{ tools: { codeMode: { enabled: true, }, },}Forma abreviada:
{ tools: { codeMode: true, },}O modo de código permanece desativado quando tools.codeMode é omitido, definido como false ou é um objeto
sem enabled: true.
Se você usa agentes em sandbox com servidores MCP configurados, também permita o
Plugin MCP integrado na política de ferramentas da sandbox, por exemplo,
tools.sandbox.tools.alsoAllow: ["bundle-mcp"]. Consulte
Configuração — ferramentas e provedores personalizados.
Defina limites explícitos para restrições mais rigorosas:
{ tools: { codeMode: { enabled: true, timeoutMs: 10000, memoryLimitBytes: 67108864, maxOutputBytes: 65536, maxSnapshotBytes: 10485760, maxPendingToolCalls: 16, snapshotTtlSeconds: 900, searchDefaultLimit: 8, maxSearchLimit: 50, }, },}Para confirmar o formato do payload do modelo durante a depuração, execute o Gateway com logs direcionados:
OPENCLAW_DEBUG_CODE_MODE=1 \OPENCLAW_DEBUG_MODEL_TRANSPORT=1 \OPENCLAW_DEBUG_MODEL_PAYLOAD=tools \openclaw gatewayCom o modo de código ativo, os nomes das ferramentas voltadas ao modelo registrados no log devem ser exec e
wait. Para obter o payload completo e censurado do provedor, adicione
OPENCLAW_DEBUG_MODEL_PAYLOAD=full-redacted durante uma breve sessão de depuração.
Visão geral técnica
O restante desta página aborda o contrato do runtime e os detalhes de implementação para mantenedores, autores de Plugins que estejam depurando a exposição de ferramentas e operadores que estejam validando implantações de alto risco.
Status do runtime
| Runtime | quickjs-wasi |
| Estado padrão | desativado |
| Estabilidade | superfície experimental do OpenClaw (o Codex Code Mode é uma superfície separada e estável do ambiente Codex) |
| Superfície-alvo | execuções genéricas de agentes do OpenClaw |
| Postura de segurança | o código do modelo é hostil |
| Garantia ao usuário | ativar o modo de código nunca recorre silenciosamente à exposição direta ampla de ferramentas |
Escopo
O modo de código controla o formato de orquestração voltado ao modelo para uma execução preparada. Ele não controla a seleção do modelo, o comportamento do canal, a autenticação, a política de ferramentas nem as implementações de ferramentas.
Dentro do escopo: definições de ferramentas diretas/de controle visíveis ao modelo, construção do catálogo oculto de ferramentas, execução guest em JavaScript/TypeScript, o runtime do worker QuickJS-WASI, callbacks do host para pesquisar/descrever/chamar, estado retomável para programas guest suspensos, limites de saída/tempo limite/memória/chamadas pendentes/snapshot e projeção de telemetria/trajetória para chamadas de ferramentas aninhadas.
Fora do escopo: execução remota de código nativa do provedor, semântica de execução de shell, alteração da autorização existente de ferramentas, scripts persistentes criados pelo usuário, acesso a gerenciador de pacotes/arquivos/rede/módulos no código guest e reutilização direta dos componentes internos do Codex Code Mode.
Ferramentas controladas pelo provedor, como sandboxes Python remotas, são ferramentas separadas. Consulte Execução de código.
Termos
- Modo de código: o modo de runtime do OpenClaw que oculta ferramentas do modelo compatíveis com o catálogo
e expõe
exec,waite as ferramentas exclusivamente diretas necessárias. - Runtime guest: a VM JavaScript QuickJS-WASI que avalia o código do modelo.
- Ponte do host: a superfície restrita de callbacks compatíveis com JSON, do código guest de volta ao OpenClaw.
- Catálogo: a lista de ferramentas efetivas no escopo da execução após a resolução normal de políticas de ferramentas, Plugins, MCP e ferramentas de clientes.
- Chamada de ferramenta aninhada: uma chamada de ferramenta feita pelo código guest por meio da ponte do host.
- Snapshot: estado serializado da VM QuickJS-WASI salvo para que
waitpossa continuar uma execução suspensa do modo de código.
Configuração
tools.codeMode.enabled é a condição de ativação; definir outros campos não
ativa o recurso por si só.
| Campo | Padrão | Limite |
|---|---|---|
enabled |
false |
booleano; somente true ativa o modo de código |
runtime |
"quickjs-wasi" |
único valor compatível |
mode |
"only" |
expõe ferramentas diretas/de controle e cataloga as demais |
languages |
["javascript", "typescript"] |
qualquer subconjunto das duas |
timeoutMs |
10000 |
100-60000 |
memoryLimitBytes |
67108864 |
1048576-1073741824 |
maxOutputBytes |
65536 |
1024-10485760 |
maxSnapshotBytes |
10485760 |
1024-268435456 |
maxPendingToolCalls |
16 |
1-128 |
snapshotTtlSeconds |
900 |
1-86400 |
searchDefaultLimit |
8 |
limitado a maxSearchLimit |
maxSearchLimit |
50 |
1-50 |
Se o modo de código estiver ativado, mas o QuickJS-WASI não puder ser carregado, o OpenClaw falhará de forma fechada nessa execução; ele não exporá silenciosamente as ferramentas normais como alternativa.
Ativação
O modo de código é avaliado depois que a política efetiva de ferramentas é conhecida e antes que a solicitação final ao modelo seja montada:
- Resolva o agente, o modelo, o provedor, a sandbox, o canal, o remetente e a política da execução.
- Construa a lista efetiva de ferramentas do OpenClaw, adicionando Plugins, ferramentas MCP e ferramentas de clientes elegíveis.
- Aplique a política de permissão/negação.
- Se
tools.codeMode.enabledfor falso, prossiga com a exposição normal das ferramentas. - Se estiver ativado e as ferramentas estiverem ativas para a execução, mantenha as ferramentas exclusivamente diretas necessárias e registre no catálogo do modo de código todas as ferramentas efetivas elegíveis para o catálogo.
- Remova as ferramentas catalogadas da lista visível ao modelo; adicione
execewaitjunto às ferramentas exclusivamente diretas mantidas.
Execuções que intencionalmente não têm ferramentas (chamadas brutas ao modelo, disableTools: true
ou uma lista tools.allow vazia) não ativam a superfície do modo de código mesmo
quando tools.codeMode.enabled: true está configurado. O modo de código e o OpenClaw Tool
Search são mutuamente exclusivos em uma execução; se o modo de código for ativado, a
Compaction do Tool Search não será aplicada.
O catálogo do modo de código é limitado ao escopo da execução e não deve vazar ferramentas de outro agente, sessão, remetente ou execução.
Ferramentas visíveis ao modelo
Quando o modo de código está ativo, o modelo vê exec, wait e qualquer ferramenta exclusivamente
direta necessária. Todas as outras ferramentas habilitadas ficam ocultas da lista de ferramentas voltada ao
modelo e são registradas no catálogo do modo de código.
Use exec para orquestração de ferramentas, junção de dados, loops, chamadas aninhadas paralelas
e transformações estruturadas. Use wait somente quando exec retornar um resultado retomável
waiting.
exec
exec inicia uma célula do modo de código e retorna um resultado. O código de entrada é gerado pelo modelo
e deve ser tratado como hostil.
Entrada:
type CodeModeExecInput = { code?: string; command?: string; language?: "javascript" | "typescript";};Regras:
- Um dos campos
codeoucommanddeve conter um valor não vazio. codeé o campo documentado voltado ao modelo.commandé aceito como um alias compatível com exec para políticas de hooks e reescritas confiáveis (a ferramenta normal de execução de shell do OpenClaw também usa um campocommand); quando ambos estão presentes, os valores devem ser iguais.- O padrão de
languageé"javascript"; o esquema o expõe como uma enumeração simples de strings ("javascript" | "typescript"), não como uma uniãooneOf/anyOf, pois alguns provedores rejeitam esses formatos. - Se
languagefor"typescript", o OpenClaw transpila o código antes da avaliação. execrejeitaimport,require, importação dinâmica e padrões de carregadores de módulos.execnunca expõe recursivamente a implementação normal deexecdo shell.- Eventos de hook do
execexterno do modo de código incluemtoolKind: "code_mode_exec"etoolInputKind: "javascript" | "typescript"(quando conhecido), para que as políticas possam distinguir células do modo de código de chamadas deexecno estilo shell que compartilham o mesmo nome de ferramenta.
Resultado:
type CodeModeResult = CodeModeCompletedResult | CodeModeWaitingResult | CodeModeFailedResult; type CodeModeCompletedResult = { status: "completed"; value: unknown; output?: CodeModeOutput[]; telemetry: CodeModeTelemetry;}; type CodeModeWaitingResult = { status: "waiting"; runId: string; reason: "pending_tools" | "yield"; pendingToolCalls?: CodeModePendingToolCall[]; output?: CodeModeOutput[]; telemetry: CodeModeTelemetry;}; type CodeModeFailedResult = { status: "failed"; error: string; code?: CodeModeErrorCode; output?: CodeModeOutput[]; telemetry: CodeModeTelemetry;};exec retorna waiting quando a VM QuickJS é suspensa com um estado retomável que
ainda requer uma continuação visível para o modelo; o resultado inclui um runId para
wait. As chamadas da ponte de namespace, incluindo chamadas de namespace MCP, são processadas automaticamente
na mesma chamada exec/wait enquanto estiverem prontas, permitindo um código compacto
o bloco pode chamar uma ferramenta MCP sem forçar uma chamada de ferramenta do modelo por namespace
aguardado.
exec retorna completed somente quando a VM convidada não tem nenhum trabalho pendente e o
valor final é compatível com JSON após a execução do adaptador de saída do OpenClaw.
wait
wait retoma uma VM em modo de código suspensa.
Entrada:
type CodeModeWaitInput = { runId: string;};A saída é a mesma união CodeModeResult retornada por exec.
wait existe porque as ferramentas aninhadas do OpenClaw podem ser lentas, interativas, sujeitas a aprovação
ou transmitir atualizações parciais; o modelo não deve precisar manter uma longa
chamada exec aberta enquanto o host aguarda trabalho externo.
O snapshot/restauração do QuickJS-WASI é o mecanismo de retomada:
execavalia o código até a conclusão, falha ou suspensão.- Na suspensão, o OpenClaw cria um snapshot da VM do QuickJS e registra o trabalho pendente do host.
- Quando o trabalho pendente é concluído,
waitrestaura o snapshot da VM e registra novamente os callbacks do host usando nomes estáveis. - O OpenClaw entrega os resultados das ferramentas aninhadas à VM restaurada e processa os trabalhos pendentes do QuickJS.
waitretornacompleted,failedou outro resultadowaiting.
Os snapshots são estados de execução, não artefatos do usuário: eles residem apenas em um mapa no processo (sem gravação em banco de dados ou disco), têm tamanho limitado, expiram e são restritos à execução e à sessão que os criaram.
wait falha (como um resultado failed) quando:
runIdé desconhecido ou seu snapshot já expirou.- o chamador não está no mesmo escopo de execução/sessão que a execução suspensa.
- um
waitjá está em andamento para esserunId. - a restauração do QuickJS-WASI falha.
- a retomada excederia
maxOutputBytesoumaxSnapshotBytes.
API do runtime convidado
declare const ALL_TOOLS: ToolCatalogEntry[];declare const tools: ToolCatalog;declare const MCP: Record<string, unknown>;declare const namespaces: Record<string, unknown>; declare function text(value: unknown): void;declare function json(value: unknown): void;declare function yield_control(reason?: string): Promise<void>;ALL_TOOLS contém metadados compactos do catálogo com escopo da execução; por padrão, ele não
contém esquemas completos.
type ToolCatalogEntry = { id: string; name: string; label?: string; description: string; source: "openclaw" | "mcp" | "client"; sourceName?: string;};As ferramentas de Plugin usam source: "openclaw" com sourceName definido como o id do
Plugin proprietário; não há um valor de origem "plugin" separado. source: "mcp" é
usado apenas para entradas MCP nos metadados sourceName/mcp (e é filtrado
de ALL_TOOLS/tools.*; veja abaixo).
O esquema completo é carregado somente sob demanda:
type ToolCatalogEntryWithSchema = ToolCatalogEntry & { parameters: unknown;};Auxiliares de catálogo:
type ToolCatalog = { search(query: string, options?: { limit?: number }): Promise<ToolCatalogEntry[]>; describe(id: string): Promise<ToolCatalogEntryWithSchema>; call(id: string, input?: unknown): Promise<unknown>; [safeToolName: string]: unknown;};As funções de conveniência das ferramentas são instaladas somente para nomes seguros inequívocos:
const files = await tools.search("read local file");const fileRead = await tools.describe(files[0].id);const content = await tools.call(fileRead.id, { path: "README.md" }); // Se o catálogo oculto tiver uma entrada `web_search` inequívoca:const hits = await tools.web_search({ query: "OpenClaw code mode" });As entradas do catálogo MCP não podem ser chamadas por meio de tools.call(...) nem de funções de
conveniência no modo de código; elas são expostas somente por meio do namespace MCP
gerado. Arquivos de declaração no estilo TypeScript estão disponíveis por meio da superfície de arquivos virtuais
API somente leitura, permitindo que os agentes inspecionem as assinaturas MCP
sem adicionar esquemas MCP ao prompt:
const files = await API.list("mcp");const githubApi = await API.read("mcp/github.d.ts"); const issue = await MCP.github.createIssue({ owner: "openclaw", repo: "openclaw", title: "Investigue os logs do Gateway",}); const snapshot = await MCP.chromeDevtools.takeSnapshot({ output: "markdown" });const resource = await MCP.docs.resources.read({ uri: "memo://one" });const prompt = await MCP.docs.prompts.get({ name: "brief", arguments: { topic: "release" },});API.read("mcp/<server>.d.ts") retorna declarações compactas inferidas dos metadados das ferramentas MCP:
type McpToolResult = { content?: unknown[]; structuredContent?: unknown; isError?: boolean; [key: string]: unknown;}; declare namespace MCP.github { /** Retorna este cabeçalho de API no estilo TypeScript. */ function $api(toolName?: string, options?: { schema?: boolean }): Promise<McpApiHeader>; /** * Cria uma issue no GitHub. * @param owner Proprietário do repositório * @param repo Nome do repositório * @param title Título da issue */ function createIssue(input: { owner: string; repo: string; title: string; body?: string; }): Promise<McpToolResult>;}Os arquivos de declaração são virtuais e não são gravados no workspace nem no diretório de estado. Para cada chamada exec no modo de código, o OpenClaw cria o catálogo de ferramentas com escopo da execução, mantém as entradas MCP visíveis, renderiza mcp/index.d.ts e um mcp/<server>.d.ts para cada servidor visível e injeta essa pequena tabela somente leitura no worker QuickJS. O código convidado vê apenas o objeto API: API.list(prefix?) retorna metadados de arquivos, e API.read(path) retorna o conteúdo da declaração selecionada. Caminhos desconhecidos e segmentos ./.. são rejeitados.
Isso mantém esquemas MCP grandes fora do prompt do modelo: o agente descobre que a API virtual existe pela descrição da ferramenta exec, lê apenas o arquivo de declaração necessário e então chama MCP.<server>.<tool>() com um argumento de objeto. MCP.<server>.$api() permanece disponível como fallback inline para uma resposta de esquema de uma única ferramenta dentro do programa.
O runtime convidado nunca vê objetos do host diretamente. Entradas e saídas atravessam a ponte como valores compatíveis com JSON, com limites de tamanho explícitos.
Namespaces internos
Namespaces internos fornecem ao modo de código uma API de domínio concisa sem adicionar mais ferramentas visíveis ao modelo. Uma integração controlada pelo loader registra um namespace como Issues ou Calendar; o código convidado então chama esse namespace dentro do programa QuickJS, enquanto o modelo continua vendo a superfície compacta de controle/direta.
Por enquanto, os namespaces são internos. Não há uma API pública de namespace no SDK de plugins: namespaces de plugins externos precisam de um contrato controlado pelo loader para que a identidade do plugin, os manifestos instalados, o estado de autenticação e os descritores de catálogo em cache não fiquem dessincronizados das ferramentas do plugin que sustentam o namespace. O modo de código do core controla apenas o sandbox, a serialização, a restrição pelo catálogo e o despacho da ponte.
O código convidado pode usar tanto o global direto quanto o mapa namespaces:
const open = await Issues.list({ state: "open" });const alsoOpen = await namespaces.Issues.list({ state: "open" });return { count: open.length, alsoCount: alsoOpen.length };Ciclo de vida do registro
O registro de namespaces é local ao processo e indexado pelo id do namespace:
- Um loader confiável chama
registerCodeModeNamespaceForPlugin(pluginId, registration). - O modo de código cria o
ToolSearchRuntimeoculto para a execução e lê seu catálogo com escopo da execução. createCodeModeNamespaceRuntime(ctx, catalog)mantém apenas os registros cujosrequiredToolNamesestão todos visíveis e pertencem ao mesmopluginId.- Cada namespace visível chama
createScope(ctx)para a execução atual, recebendo contexto de execução comoagentId,sessionKey,sessionId,runId, configuração e estado de cancelamento. - Os dados do escopo são serializados em um descritor simples e injetados no QuickJS como globais diretos e
namespaces.<globalName>. - As chamadas do código convidado são suspensas pela ponte do worker, resolvem o caminho do namespace no host, mapeiam a chamada para uma ferramenta declarada do catálogo pertencente ao plugin e executam essa ferramenta por meio de
ToolSearchRuntime.callExactId. - As chamadas prontas da ponte de namespaces são drenadas automaticamente dentro da chamada ativa
exec/wait; se ainda houver trabalho de namespace pendente ao atingir o tempo limite ou se o código convidado ceder explicitamente,waitretoma posteriormente o mesmo runtime de namespace. - O rollback ou a desinstalação do plugin chama
clearCodeModeNamespacesForPlugin(pluginId)para que globais obsoletos não sobrevivam a uma falha no carregamento do plugin.
As chamadas de namespace são chamadas de ferramentas do catálogo: elas usam os mesmos hooks de política, aprovações, tratamento de cancelamento, telemetria, projeção da transcrição e comportamento de suspensão/retomada que tools.call(...).
Formato do registro
Registre namespaces pela integração que controla as ferramentas subjacentes. Mantenha o escopo pequeno e exponha somente verbos de domínio que correspondam a ferramentas declaradas no catálogo.
createCodeModeNamespaceTool, registerCodeModeNamespaceForPlugin,} from "../agents/code-mode-namespaces.js"; const pluginId = "github"; registerCodeModeNamespaceForPlugin(pluginId, { id: "github-issues", globalName: "Issues", description: "Auxiliares de issues do GitHub para o repositório atual.", requiredToolNames: ["github_list_issues", "github_update_issue"], prompt: "Use Issues.list(params) e Issues.update(number, patch).", createScope: (ctx) => ({ repository: ctx.config, list: createCodeModeNamespaceTool("github_list_issues", ([params]) => params ?? {}), update: createCodeModeNamespaceTool("github_update_issue", ([number, patch]) => ({ number, patch, })), }),});createCodeModeNamespaceTool(toolName, inputMapper) marca um membro do escopo como uma função de namespace chamável. O inputMapper opcional recebe os argumentos do código convidado e retorna o objeto de entrada para a ferramenta de catálogo subjacente; sem ele, o primeiro argumento do código convidado é usado, ou {} quando omitido.
Funções brutas do host são rejeitadas antes da execução do código convidado:
createScope: () => ({ // Incorreto: isso ignora o ciclo de vida da ferramenta de catálogo e será rejeitado. list: async () => githubClient.listIssues(),});Propriedade e visibilidade
A propriedade do namespace é vinculada ao pluginId do chamador do registro. requiredToolNames funciona tanto como restrição de visibilidade quanto como verificação de propriedade:
- toda ferramenta obrigatória deve existir no catálogo da execução
- toda ferramenta obrigatória deve ter
sourceName === pluginId - o namespace fica oculto quando qualquer ferramenta obrigatória está ausente ou pertence a outro plugin
- cada caminho chamável pode direcionar somente para uma ferramenta mencionada em
requiredToolNames
Isso impede que outro plugin exponha um namespace registrando uma ferramenta com o mesmo nome e mantém os namespaces alinhados à política comum do agente: se a execução não puder ver as ferramentas subjacentes, ela não poderá ver o namespace.
Por exemplo, um namespace do GitHub deve ficar atrás de um plugin pertencente ao GitHub que controle a autenticação do GitHub, clientes REST/GraphQL, limites de taxa, aprovações de escrita e testes. O modo de código do core não deve incorporar APIs específicas do GitHub, tratamento de tokens ou políticas de provedor.
Regras de serialização do escopo
createScope(ctx) pode retornar um objeto simples contendo valores compatíveis com JSON, arrays, objetos aninhados e marcadores de chamada createCodeModeNamespaceTool(...). Objetos do host nunca entram diretamente no QuickJS.
O serializador rejeita:
- funções brutas
- grafos de objetos circulares
- segmentos de caminho não seguros:
__proto__,constructor,prototype, chaves vazias ou chaves contendo o separador de caminho interno - valores de
globalNameque não são identificadores JavaScript - colisões de
globalNamecom globais integradas do modo de código, comotools,namespaces,text,json,yield_control,MCP,API,ALL_TOOLSou__openclaw*
Os valores que não podem ser serializados como JSON são convertidos em valores alternativos seguros para JSON antes de atravessar a ponte. Dados binários, identificadores, soquetes, clientes e instâncias de classe devem permanecer por trás das ferramentas comuns do catálogo.
Prompts
A description e o prompt opcional do namespace são anexados ao esquema de
exec visível para o modelo somente quando o namespace está visível nessa
execução. Use-os para ensinar a menor superfície útil:
{ description: "Auxiliares do serviço de produção de ficção.", prompt: "Use Fictions.riskAudit(), Fictions.promoteIfReady(id, status) e Fictions.unpaidOver(amount).",}Mantenha os prompts relacionados ao contrato do namespace, não à configuração de autenticação, ao histórico de implementação ou a comportamentos não relacionados do plugin.
Limpeza
Os namespaces são registros locais do processo. Remova-os quando o plugin proprietário for desabilitado, desinstalado ou revertido:
clearCodeModeNamespacesForPlugin(pluginId);A limpeza do modo de código é responsabilidade do plugin; limpe os registros
de namespace do plugin quando seu ciclo de vida terminar, em vez de manter
identificadores de desmontagem por namespace. Os testes podem chamar
clearCodeModeNamespacesForTest() para evitar o vazamento de registros entre
casos.
Lista de verificação de testes
As alterações de namespace devem abranger o limite de segurança e o comportamento do código convidado:
- o texto do prompt do namespace aparece somente quando as ferramentas subjacentes estão visíveis
- ferramentas com o mesmo nome provenientes de outro
sourceNamenão expõem o namespace - funções de escopo brutas são rejeitadas
- IDs de namespace forjados e caminhos forjados são rejeitados
- caminhos invocáveis não podem apontar para ferramentas não declaradas
- objetos aninhados e referências compartilhadas são serializados corretamente
- as chamadas de namespace são executadas por meio das ferramentas do catálogo e retornam detalhes seguros para JSON
- as falhas podem ser capturadas pelo código convidado
- chamadas de namespace suspensas são retomadas por meio de
wait - a reversão do plugin limpa os registros de namespace pertencentes a ele
Os namespaces complementam o catálogo genérico tools.search/tools.call: use
o catálogo para ferramentas arbitrárias habilitadas do OpenClaw, de plugins e
de clientes; use MCP para ferramentas MCP; use outros namespaces para APIs de
domínio documentadas e pertencentes a plugins, nas quais código conciso é mais
confiável do que consultas repetidas ao esquema.
API de saída
text(value)acrescenta uma saída legível por humanos ao arrayoutput.json(value)acrescenta um item de saída estruturado após a serialização compatível com JSON.- O valor final retornado pelo código convidado torna-se
valueem um resultadocompleted.
type CodeModeOutput = { type: "text"; text: string } | { type: "json"; value: unknown };Regras: a ordem de saída corresponde à ordem das chamadas do guest; a saída é limitada por
maxOutputBytes; valores não serializáveis são convertidos em strings simples ou
erros; valores binários não são compatíveis. Imagens e arquivos são transmitidos por
ferramentas comuns do OpenClaw, não pela ponte do modo de código.
Catálogo de ferramentas
O catálogo oculto inclui as ferramentas após a filtragem efetiva por políticas, nesta ordem: ferramentas principais do OpenClaw, ferramentas de plugins incluídos, ferramentas de plugins externos, ferramentas MCP e, por fim, ferramentas fornecidas pelo cliente para a execução atual.
Os ids do catálogo são estáveis dentro de uma execução e determinísticos entre conjuntos de ferramentas equivalentes, quando possível. Formato real:
<source>:<owner>:<tool-name>em que <source> é openclaw, mcp ou client (as ferramentas de plugins usam
openclaw com o id do plugin como <owner>; as ferramentas principais usam openclaw:core:*).
Exemplos:
openclaw:core:messageopenclaw:browser:browser_requestmcp:github:create_issueclient:app:select_fileO catálogo omite as ferramentas de controle do modo de código (exec, wait, tool_search_code,
tool_search, tool_describe, tool_call) e as ferramentas somente diretas. Os controles
não devem fazer chamadas recursivas pelo catálogo; as ferramentas somente diretas permanecem
visíveis para o modelo porque seus resultados estruturados não podem atravessar a ponte do QuickJS.
As entradas MCP permanecem no catálogo com escopo de execução para que políticas, aprovações, hooks,
telemetria, projeção da transcrição e ids exatos das ferramentas continuem compartilhados com
a execução normal de ferramentas. As visualizações voltadas ao guest ALL_TOOLS, tools.search(...),
tools.describe(...) e tools.call(...) omitem as entradas MCP. O namespace
gerado MCP.<server>.<tool>({ ...input }) é resolvido para o id exato do catálogo e despachado
pelo mesmo caminho do executor.
Interação com a Pesquisa de Ferramentas
O modo de código substitui a superfície de modelo da Pesquisa de Ferramentas do OpenClaw nas execuções em que está ativo.
Quando tools.codeMode.enabled é true e o modo de código é ativado:
- O OpenClaw não expõe
tool_search_code,tool_search,tool_describenemtool_callcomo ferramentas visíveis para o modelo. - O mesmo conceito de catalogação é transferido para o runtime do guest.
- O runtime do guest recebe metadados compactos de
ALL_TOOLSe auxiliares de pesquisa/descrição/ chamada para ferramentas que não são MCP. - As chamadas MCP usam o namespace
MCPgerado e seus cabeçalhos$api()em vez detools.call(...). - As chamadas aninhadas são despachadas pelo mesmo caminho do executor do OpenClaw usado pela Pesquisa de Ferramentas.
Consulte Pesquisa de Ferramentas para conhecer a ponte de catálogo compacto do OpenClaw que o modo de código substitui nas execuções ativas.
Nomes de ferramentas e colisões
A ferramenta exec visível para o modelo é a ferramenta do modo de código. Se a ferramenta normal
de shell exec do OpenClaw estiver habilitada, ela ficará oculta para o modelo e será catalogada como
qualquer outra ferramenta.
Dentro do runtime convidado:
tools.call("openclaw:core:exec", input)pode chamar a ferramenta de execução do shell se a política permitir.tools.exec(...)é instalado somente se a entrada do catálogo de execução do shell tiver um nome seguro inequívoco.- a ferramenta
execdo modo de código nunca fica disponível recursivamente por meio detools.
Se duas ferramentas forem normalizadas para o mesmo nome conveniente seguro, o OpenClaw omitirá a
função conveniente e exigirá tools.call(id, input).
Execução aninhada de ferramentas
Cada chamada aninhada de ferramenta atravessa a ponte do host e entra novamente no OpenClaw,
preservando: id do agente ativo, id e chave da sessão, contexto do remetente e do canal,
política de sandbox, política de aprovação, hooks before_tool_call do plugin, sinal de
interrupção, atualizações por streaming quando disponíveis e eventos de trajetória/auditoria.
As chamadas aninhadas são projetadas na transcrição como chamadas reais de ferramentas para que os pacotes de suporte mostrem o que aconteceu, com a projeção identificando a chamada da ferramenta pai do modo de código e o id da ferramenta aninhada.
Chamadas aninhadas paralelas são permitidas até maxPendingToolCalls.
Ciclo de vida da execução e do snapshot
Cada execução do modo de código é rastreada em um mapa em processo indexado por runId (não
persistido em disco nem em um banco de dados). exec/wait retornam um de três estados de
resultado: completed, waiting ou failed.
- Um resultado
waitingarmazena o snapshot do QuickJS, as solicitações pendentes da ponte e os metadados de escopo (id da execução do agente, id/chave da sessão) até quewaito retome ou ele expire. - Valores de
runIdexpirados, de sessão incorreta, de execução incorreta e desconhecidos/já em retomada não produzem um estado terminal distinto; eles aparecem como um resultadofailed(code: "invalid_input") com uma mensagem comocode mode run is unavailable or expired.oucode mode run belongs to a different session.. - O snapshot de uma execução é removido do mapa assim que ela termina como
completedoufailed, ou é descartado no encerramento do Gateway (nada sobrevive a uma reinicialização: este é um estado transitório do runtime). - Para trabalho somente leitura,
execpode definirrestartSafe: true. O OpenClaw então rejeita chamadas de catálogo com efeitos colaterais e namespaces de plugins antes da execução e marca resultados suspensos como seguros para reprodução. Se uma reinicialização interromperwait, a recuperação após reinicialização reconstruirá o turno a partir da transcrição em vez de restaurar o snapshot local do processo. O próprio turno de recuperação permanece limitado a ferramentas principais auditadas somente leitura e ferramentas de plugins explicitamente seguras para reprodução. - O OpenClaw limita o número de execuções suspensas simultaneamente por processo (64) e
rejeita novas suspensões além desse limite com
too many suspended code mode runs..
O armazenamento de snapshots é limitado por maxSnapshotBytes por execução, pelo limite por processo
de execuções suspensas mencionado acima e por snapshotTtlSeconds.
Runtime QuickJS-WASI
O OpenClaw carrega quickjs-wasi como uma dependência direta no pacote proprietário; ele
não depende de uma cópia transitiva instalada para uma dependência não relacionada.
Responsabilidades do runtime: compilar/carregar o módulo WebAssembly do QuickJS-WASI;
criar uma VM isolada por execução ou retomada do modo de código; registrar callbacks do host
com nomes estáveis; definir limites de memória e interrupção; avaliar JavaScript; processar
tarefas pendentes; criar snapshots do estado suspenso da VM; restaurar snapshots para wait;
liberar identificadores de VM e snapshots após estados terminais.
O runtime é executado em uma thread worker do Node.js, fora do loop principal de eventos do OpenClaw. Um loop infinito no convidado não deve bloquear o processo do Gateway indefinidamente; o manipulador de interrupções do worker impõe o tempo limite de relógio independentemente da cooperação do código convidado.
TypeScript
O suporte a TypeScript é apenas uma transformação de código-fonte: a entrada aceita é uma única
string de código TypeScript; a saída é uma string JavaScript avaliada pelo
QuickJS-WASI. Não há verificação de tipos, resolução de módulos nem
import/require. Os diagnósticos são retornados como resultados failed.
O compilador TypeScript é carregado de forma preguiçosa apenas para células TypeScript; células JavaScript simples e o modo de código desativado nunca o carregam.
Limite de segurança
O código do modelo é hostil. O runtime usa defesa em profundidade:
- executa o QuickJS-WASI fora do loop de eventos principal, em uma thread de trabalho
- carrega
quickjs-wasicomo uma dependência direta, não por meio do Codex nem de um pacote transitivo - não há sistema de arquivos, rede, subprocessos, importação de módulos, variáveis de ambiente nem objetos globais do host no ambiente convidado
- usa limites de memória e de interrupção do QuickJS, além de um tempo limite de relógio de parede no processo pai
- impõe limites de saída, snapshots, logs e chamadas pendentes
- serializa os valores da ponte do host por meio de um adaptador JSON restrito
- converte erros do host em erros simples no ambiente convidado, nunca em objetos do realm do host
- descarta snapshots em caso de tempo limite, cancelamento, encerramento da sessão ou expiração
- rejeita acesso recursivo a
exec,waite às ferramentas de controle do Tool Search - impede que colisões de nomes de conveniência ocultem os auxiliares do catálogo
O sandbox é uma camada de segurança; os operadores ainda podem precisar de reforço de segurança no nível do sistema operacional para implantações de alto risco.
Códigos de erro
type CodeModeErrorCode = | "invalid_input" | "runtime_unavailable" | "timeout" | "output_limit_exceeded" | "snapshot_limit_exceeded" | "internal_error";invalid_input abrange argumentos inválidos de exec/wait, linguagens desativadas,
acesso rejeitado a módulos, falhas na transformação de TypeScript, valores de runId
desconhecidos, expirados ou de escopo incorreto e execuções suspensas em excesso. runtime_unavailable
abrange um worker do QuickJS que não consegue iniciar ou encerra com código diferente de zero.
Os erros retornados ao ambiente convidado são dados simples; instâncias de Error do host, objetos
de pilha, protótipos e funções do host não atravessam para o QuickJS.
Telemetria
O campo telemetry de cada resultado informa: o tamanho do catálogo oculto e uma
divisão por origem (contagens de openclaw/mcp/client), contagens acumuladas de
pesquisas/descrições/chamadas para o catálogo da execução e os nomes de ferramentas visíveis ao modelo (exec,
wait e ferramentas retidas somente para acesso direto).
A telemetria não deve incluir segredos, valores brutos de ambiente nem entradas de ferramentas sem redação além do permitido pela política de trajetória existente do OpenClaw.
Depuração
Use o registro direcionado do transporte do modelo quando o modo de código se comportar de maneira diferente de uma execução normal de ferramenta:
OPENCLAW_DEBUG_CODE_MODE=1 \OPENCLAW_DEBUG_MODEL_TRANSPORT=1 \OPENCLAW_DEBUG_MODEL_PAYLOAD=tools \OPENCLAW_DEBUG_SSE=events \openclaw gatewayPara depurar o formato do payload, use OPENCLAW_DEBUG_MODEL_PAYLOAD=full-redacted.
Isso registra um snapshot JSON limitado e redigido da solicitação ao modelo; use-o apenas
durante a depuração, pois prompts e texto de mensagens ainda podem aparecer.
Para depuração de stream, use OPENCLAW_DEBUG_SSE=peek para registrar os cinco primeiros
eventos SSE com dados sensíveis ocultados. O modo de código também falha de forma segura se o payload final do provedor
não contiver exatamente um exec, um wait e somente ferramentas
direct-only aprovadas após a ativação da superfície do modo de código.
Estrutura da implementação
- contrato de configuração:
tools.codeMode - construtor de catálogo: ferramentas efetivas convertidas em entradas compactas e mapa de IDs
- adaptador da superfície do modelo: substitui as ferramentas visíveis por ferramentas de controle/direct-only
- adaptador de runtime QuickJS-WASI: carregar, avaliar, criar snapshot, restaurar, descartar
- supervisor de workers: tempo limite, cancelamento, isolamento de falhas
- adaptador da ponte: callbacks do host compatíveis com JSON e entrega de resultados
- adaptador de transformação TypeScript
- armazenamento de snapshots: TTL, limites de tamanho, escopo de execução/sessão
- projeção de trajetória para chamadas de ferramentas aninhadas
- contadores de telemetria e diagnósticos
A implementação reutiliza conceitos de catálogo e executor da Busca de Ferramentas, mas
não usa um processo filho node:vm como sandbox.
Lista de verificação de validação
A cobertura do modo de código deve comprovar:
- a configuração desabilitada mantém inalterada a exposição existente de ferramentas
- a configuração como objeto sem
enabled: truemantém o modo de código desabilitado - a configuração habilitada expõe
exec,waite somente as ferramentas direct-only necessárias ao modelo quando as ferramentas estão ativas para a execução - execuções brutas sem ferramentas,
disableToolse listas de permissões vazias não acionam a imposição do payload do modo de código - todas as ferramentas efetivas não MCP elegíveis para o catálogo aparecem em
ALL_TOOLS - as ferramentas direct-only permanecem visíveis ao modelo e não aparecem em
ALL_TOOLS - as ferramentas negadas não aparecem em
ALL_TOOLS tools.search,tools.describeetools.callfuncionam para ferramentas do OpenClawAPI.list("mcp")eAPI.read("mcp/<server>.d.ts")expõem declarações MCP no estilo TypeScript sem uma chamada de ponte/ferramenta- o
$api()do namespace MCP permanece disponível como fallback inline para esquemas - as chamadas do namespace MCP funcionam para ferramentas MCP visíveis com uma entrada de objeto, enquanto
as entradas diretas do catálogo MCP não aparecem em
tools.* - as ferramentas de controle da Busca de Ferramentas ficam ocultas tanto da superfície do modelo quanto do catálogo oculto
- as chamadas aninhadas preservam o comportamento de aprovação e dos hooks
- o
execdo shell fica oculto do modelo, mas pode ser chamado pelo ID do catálogo quando permitido execewaitrecursivos do modo de código não podem ser chamados pelo código convidado- a entrada TypeScript é transformada e avaliada sem carregar o TypeScript nos caminhos desabilitados ou exclusivos de JavaScript
- o acesso a
import,require, sistema de arquivos, rede e ambiente falha - loops infinitos atingem o tempo limite e não podem bloquear o Gateway
- falhas no limite de memória encerram a VM convidada
- os limites de saída e snapshot são aplicados a chamadas concluídas e suspensas
waitretoma um snapshot suspenso e retorna o valor final- valores
runIdexpirados, cancelados, de sessão incorreta e desconhecidos falham - a reprodução e a persistência da transcrição preservam as chamadas de controle do modo de código
- a transcrição e a telemetria mostram claramente as chamadas de ferramentas aninhadas
Plano de testes E2E
Execute estes testes como testes de integração ou de ponta a ponta ao alterar o runtime:
- Inicie um Gateway com
tools.codeMode.enabled: false. - Envie um turno do agente com um pequeno conjunto de ferramentas diretas.
- Verifique se as ferramentas visíveis ao modelo permanecem inalteradas.
- Reinicie com
tools.codeMode.enabled: true. - Envie um turno do agente com ferramentas de teste do OpenClaw, de plugins, MCP e do cliente.
- Verifique se a lista de ferramentas visíveis ao modelo é composta por
exec,waite somente pelas ferramentas direct-only configuradas. - Em
exec, leiaALL_TOOLSe verifique se as ferramentas de teste efetivas elegíveis para o catálogo estão presentes, enquanto as ferramentas direct-only estão ausentes. - Em
exec, chame ferramentas do OpenClaw/de plugins/do cliente por meio detools.search,tools.describeetools.call. - Em
exec, chameAPI.list("mcp")eAPI.read("mcp/<server>.d.ts")e verifique se os arquivos de declaração descrevem as ferramentas MCP visíveis. - Em
exec, chame ferramentas MCP por meio deMCP.<server>.<tool>({ ...input })e verifique se as entradas diretas do catálogo MCP estão ausentes deALL_TOOLSetools.*. - Verifique se as ferramentas negadas estão ausentes e não podem ser chamadas por um ID presumido.
- Inicie uma chamada de ferramenta aninhada que seja resolvida depois que
execretornarwaiting. - Chame
waite verifique se a VM restaurada recebe o resultado da ferramenta. - Verifique se a resposta final contém a saída produzida após a restauração.
- Verifique se o tempo limite, o cancelamento e a expiração do snapshot limpam o estado do runtime.
- Exporte a trajetória e verifique se as chamadas aninhadas estão visíveis sob a chamada pai do modo de código.
Alterações somente na documentação desta página ainda devem executar pnpm check:docs.