/**
* Agent CLI Adapter — executa nós do grafo delegando a um agente de codificação
* JÁ INSTALADO E AUTENTICADO na máquina (hoje: `claude`, o Claude Code CLI),
* em modo print (não interativo), por subprocesso.
*
* POR QUE ISSO EXISTE
* -------------------
* Antes deste adapter, `izanagi run` sem API key caía em
* `createHeadlessProducer`: o grafo era planejado de verdade, roteado de
* verdade, verificado de verdade — e os nós eram SIMULADOS. O framework
* orquestrava, mas não executava trabalho. Quem não quer colar uma chave de
* API nem subir um modelo local ficava com um planejador, não com um runtime.
*
* O agente de codificação que a pessoa já usa no terminal resolve isso: ele já
* está autenticado (assinatura/OAuth do próprio CLI), já roda local, e expõe
* modo não interativo com telemetria de uso. Izanagi não precisa de chave
* nenhuma — precisa de um executor. Este é o executor de custo zero de setup.
*
* NÃO é "mais um provider de LLM": é uma camada de PROCESSO. A diferença
* prática está no que o CLI aceita e o que uma API HTTP não aceita:
*
* Izanagi flag do `claude`
* ------------------------- --------------------------------
* modelo do papel --model
* teto de custo do nó --max-budget-usd
* política de tools --restricted / --tools
* escrita (opt-in explícito) --permission-mode acceptEdits
* sem estado residual --no-session-persistence / --strict-mcp-config
* telemetria real --output-format json (usage + total_cost_usd)
*
* O custo volta MEDIDO pelo próprio CLI (`total_cost_usd`), não estimado por
* tabela de preço — é a única superfície do runtime onde o custo é fato.
*
* DECISÕES QUE PARECEM DETALHE E NÃO SÃO
* --------------------------------------
* 1. Prompt vai por STDIN, nunca por argv. O system prompt de um nó com chain
* de skills passa de 30KB; o limite de linha de comando do Windows é 32767
* caracteres para o comando inteiro. Por argv, o run quebraria justamente
* nos nós mais ricos. Por stdin não existe limite prático.
*
* 2. Default é `--restricted --tools ""`: nenhuma tool, nenhuma execução de
* comando, nenhum settings do projeto carregado. Medido nesta máquina, isso
* derruba o system prompt do CLI de 20848 para 4095 tokens de entrada
* (US$ 0,042 -> US$ 0,005 na mesma pergunta). Além de mais barato é mais
* determinístico e mais seguro: o produtor de artefato de um nó não precisa
* de shell. Quem quiser grounding no repositório liga tools de leitura;
* quem quiser escrita precisa pedir escrita.
*
* 3. `spawn` sem shell, argv em array: o objetivo do usuário entra como dado,
* nunca como texto interpretado por um shell.
*
* 4. Guarda de profundidade: um `izanagi run` disparado DE DENTRO de uma sessão
* do agente pode spawnar o agente (profundidade 0 -> 1). O que não pode é a
* recursão continuar. Estourado o teto, o adapter fica `configured: false` e
* o runtime degrada para headless com aviso, em vez de estourar no meio do
* grafo.
*/
import type { CompletionOptions, CompletionResult, ModelAdapter } from './client.js';
/** Teto de profundidade de recursão (agente -> izanagi -> agente -> ...). */
export declare const DEFAULT_MAX_DEPTH = 1;
/**
* Timeout por chamada. Um agente de codificação em modo print pode pensar por
* bem mais tempo que um POST de chat completion (ele tem loop de raciocínio
* próprio), então o default é maior que o do cliente HTTP e tem env separada.
*/
export declare const DEFAULT_TIMEOUT_MS = 300000;
/** Teto de stdout acumulado (proteção de memória contra saída patológica). */
export declare const MAX_STDOUT_BYTES: number;
/**
* Custo fixo de tokens que o CLI hospedeiro cobra por chamada, MEDIDO nesta
* máquina com `--restricted --tools ""` (o default do adapter): 4095 tokens de
* entrada só do system prompt do próprio agente, antes de qualquer instrução
* do Izanagi. Com as customizações do projeto carregadas o número foi 20848.
*
* O runtime precisa desse número porque o orçamento de um nó não é só o
* prompt que o Izanagi escreve: um `--budget` pequeno estoura no primeiro nó e
* o usuário lê "orçamento da fase execution esgotado" sem saber por quê.
*/
export declare const AGENT_CLI_OVERHEAD_TOKENS = 4095;
/**
* Unidade de planejamento: quanto custa UM nó neste executor.
*
* Medido nesta máquina em 2026-09-10, com `--agent-tools none`:
*
* | Caso | Tokens do nó |
* |---------------------------------------------------|--------------|
* | primeira medição, nó isolado | ~18.000 |
* | modo `direct` (três execuções do mesmo objetivo) | 19.799 · 20.706 · 20.114 |
* | modo `orchestrated`, nó de specialist com survey no contexto | ~26.500 (106.140 em 4 chamadas) |
* | idem, com retentativa | ~29.400 (147.140 em 5 chamadas) |
*
* O valor é o do TOPO da faixa, e não a média das medições, porque o erro não é
* simétrico: um teto folgado não gasta um token a mais (o gasto é o que o nó
* consome, e quem limita dinheiro é `--max-cost`, cobrado sobre custo MEDIDO),
* enquanto um teto curto aborta o run depois de todo o custo já ter sido pago.
* Foi exatamente o que aconteceu duas vezes com 18.000: um run orchestrated
* produziu cinco artefatos válidos (7,4KB + 13,7KB + 23,7KB) e terminou sem
* gravar arquivo nenhum.
*
* O nó do modo `direct` é mais barato que isto, e tudo bem: o teto dele sobra.
* Dimensionar pelo caso mais barato é que quebraria o caso mais caro.
*/
export declare const AGENT_CLI_TOKENS_PER_NODE = 30000;
/**
* Menor fatia que a fase `execution` recebe do teto do run, derivada dos
* próprios pesos do alocador.
*
* O piso usa a MENOR das complexidades, e não a do meio: um piso que só vale
* para uma complexidade é um piso que falha nas outras duas, e falhar por
* orçamento mal declarado é o pior tipo de falha, porque parece falha do
* modelo.
*/
export declare const MIN_EXECUTION_PHASE_SHARE: number;
/** O mesmo para a fase que paga as retentativas. */
export declare const MIN_RECOVERY_PHASE_SHARE: number;
/** Tokens que um nó precisa ter disponível para caber, já com a folga. */
export declare function nodeCostWithHeadroom(policy: AgentCLIToolPolicy): number;
/**
* Folga sobre o consumo MEDIDO.
*
* A medição é de execuções observadas, e a próxima pode ser maior: o gasto de
* um nó varia com o tamanho da resposta e com quanto contexto o Context
* Resolver injetou. A folga cobre essa variação sem que a constante precise ser
* reescrita a cada run — que é o erro que esta linha já cometeu uma vez, quando
* o piso era a média medida e reprovava metade das execuções.
*/
export declare const AGENT_CLI_VARIANCE_HEADROOM = 1.3;
/**
* Piso de `--budget` recomendado para um run de um nó neste executor, sem
* tools: consumo medido, mais folga de variância, dividido pela menor fatia da
* fase `execution`, arredondado para o milhar.
*/
export declare const AGENT_CLI_MIN_RECOMMENDED_BUDGET: number;
/**
* O mesmo nó com `--agent-tools read`, MEDIDO: 47,4k de entrada e 20,3k de
* saída (67,7k no total). Ler o repositório multiplica o custo por ~3,8x
* porque o agente faz várias voltas de tool antes de responder.
*
* O número existe para que o aviso de orçamento seja honesto por política em
* vez de citar um único valor que só vale para o caso sem tools.
*/
export declare const AGENT_CLI_TOKENS_PER_NODE_WITH_TOOLS = 68000;
/** Piso recomendado por política de tools (mesma conta do caso sem tools). */
export declare const AGENT_CLI_MIN_BUDGET_WITH_TOOLS: number;
/** Piso de `--budget` recomendado para um nó, dada a política de tools. */
export declare function recommendedBudget(policy: AgentCLIToolPolicy): number;
/** Tokens medidos de um nó, dada a política de tools. */
export declare function measuredTokensPerNode(policy: AgentCLIToolPolicy): number;
/** Política de tools do subprocesso. */
export type AgentCLIToolPolicy = 'none' | 'read' | 'write';
/** Tools de leitura usadas em `policy: 'read'` (grounding no repositório real). */
export declare const READ_TOOLS: string[];
/** Tools de `policy: 'write'`: leitura + escrita de arquivo. Sem Bash, de propósito. */
export declare const WRITE_TOOLS: string[];
/** Profundidade atual da cadeia de subprocessos de agente. */
export declare function currentDepth(env?: NodeJS.ProcessEnv): number;
/**
* Política de tools declarada pelo ambiente.
*
* `write` NÃO é acessível por acidente: exige o valor literal `write`, porque
* é o único valor que autoriza o subprocesso a alterar arquivos do projeto.
*/
export declare function toolPolicyFromEnv(env?: NodeJS.ProcessEnv): AgentCLIToolPolicy;
/**
* Dentro de um test runner o executor fica DESLIGADO por padrão.
*
* Sem isto, qualquer teste que chame a CLI em processo (`cli.test`,
* `cli-hitl.test`) passaria a spawnar o agente de verdade e a suíte gastaria
* cota real da assinatura de quem rodou `npm test` — medido: um único teste de
* compatibilidade de flag saiu de milissegundos para 28 segundos de chamada de
* modelo. O default seguro é o inverso: teste roda headless.
*
* `IZANAGI_AGENT_CLI_IN_TESTS=1` libera, para quem quer justamente um teste de
* integração contra o CLI instalado.
*/
export declare function isSuppressedInTests(env?: NodeJS.ProcessEnv): boolean;
/**
* Procura um executável no PATH sem shell e sem `which`/`where` (spawnar um
* processo só para descobrir se dá para spawnar outro é caro e, no Windows,
* depende de qual shell atende).
*
* No Windows testa as extensões do PATHEXT: `claude` no disco é `claude.exe`,
* e `fs.existsSync('claude')` daria falso negativo.
*/
export declare function findExecutable(bin: string, env?: NodeJS.ProcessEnv): string | null;
/** Requisição normalizada que o spec traduz para argv do CLI concreto. */
export interface AgentCLIRequest {
model: string;
/** Instruções de operação do nó (system prompt compilado pelo Izanagi). */
system?: string;
/** Mensagem do usuário/objetivo. */
prompt: string;
toolPolicy: AgentCLIToolPolicy;
/** Teto de custo desta chamada, em USD. Ausente = sem teto no subprocesso. */
maxCostUsd?: number;
/** Agente nativo do host a assumir a sessão (passthrough opcional). */
agent?: string;
}
/** Resposta normalizada extraída do stdout do CLI. */
export interface AgentCLIResponse {
text: string;
/** Tokens realmente consumidos (entrada + criação/leitura de cache + saída). */
tokens: number;
/** Tokens servidos do cache de prompt, quando o CLI reporta. */
cachedTokens?: number;
/** Custo medido pelo próprio CLI, em USD. */
costUsd?: number;
/** Modelo que o CLI de fato usou, quando reportado. */
model?: string;
}
export interface AgentCLISpec {
/** Id do provider no ModelRouter/LLMClient (ex.: `claude-cli`). */
readonly provider: string;
/** Nome do executável no PATH (sem extensão). */
readonly bin: string;
/** Nome legível para mensagens ao usuário. */
readonly label: string;
/** Como instalar/autenticar, citado quando o binário não é encontrado. */
readonly install: string;
/**
* CLIs conhecidos podem ser detectados sem que Izanagi finja conhecer seu
* protocolo de execução. Specs discovery-only aparecem no diagnóstico, mas
* nunca entram no roteamento nem são marcados como disponíveis.
*/
readonly executionSupported?: boolean;
buildArgs(req: AgentCLIRequest): string[];
/** Texto enviado por stdin (prompt e, se necessário, o system embutido). */
buildStdin(req: AgentCLIRequest): string;
/** Lança `Error` quando o próprio CLI reportou falha. */
parse(stdout: string): AgentCLIResponse;
}
/**
* Delimitadores do bloco de instruções enviado por stdin.
*
* O system prompt do Izanagi não cabe em argv (ver cabeçalho), e o CLI não lê
* system por stdin. A saída é mandar o bloco marcado no corpo da mensagem e
* usar `--append-system-prompt` (curto, cabe em argv) apenas para dizer ao
* agente COMO tratar esse bloco. Assim a instrução continua tendo estatuto de
* instrução, sem depender de flag não documentada.
*/
export declare const SYSTEM_OPEN = "";
export declare const SYSTEM_CLOSE = "";
export declare const TASK_OPEN = "";
export declare const TASK_CLOSE = "";
/**
* Marca de falha do EXECUTOR (e não do trabalho): o processo terminou sem
* chegar à API. Quem carrega o texto é a mensagem de erro, e quem a lê é o
* classificador do healing.
*/
export declare const EXECUTOR_UNAVAILABLE = "executor indispon\u00EDvel";
/**
* Traduz a saída de um CLI que terminou com código diferente de zero.
*
* Antes, 400 caracteres crus do stdout viravam a mensagem de erro do nó. Numa
* recusa do CLI hospedeiro isso é o envelope JSON de telemetria: o usuário lia
* `saiu com código 1: {"duration_api_ms":0,"stop_reason":"stop_sequence",...}`
* e não tinha como saber que nada foi executado.
*
* O sinal está no próprio envelope: `duration_api_ms` zero com uso zero
* significa que o processo nem falou com a API — quota, autenticação ou
* indisponibilidade. Isso é falha de EXECUTOR, não do trabalho do nó, e a
* diferença importa porque retentar não conserta a primeira e pode consertar a
* segunda.
*/
export declare function describeFailure(code: number | null, stderr: string, stdout: string): string;
/** Contrato de operação passado em argv (curto por necessidade). */
export declare const CLAUDE_CONTRACT: string;
/**
* Acréscimo ao contrato quando o subprocesso roda SEM tool nenhuma.
*
* Medido em 2026-09-10, num nó `security-report` com `--agent-tools none`: o
* artefato gravado foram onze linhas imitando uma transcrição de tool-calls
* (`**Tool Call: rg -il "jwt"**`, `Status: Completed`, `Terminal:` e uma lista
* de arquivos), citando `src/runtime/security/tokens.ts` e
* `webhookSecurity.ts` — dois arquivos que não existem neste repositório. Sem
* tools, o modelo não pode ler nada; o que ele fez foi ENCENAR a leitura.
*
* O aviso é preventivo e não substitui a detecção: `validateArtifact` reprova
* a transcrição encenada de qualquer forma, porque um contrato no prompt é um
* pedido, e um artefato entregue é um fato.
*/
export declare const NO_TOOLS_CONTRACT: string;
/** Contrato completo para uma política de tools. */
export declare function contractFor(policy: AgentCLIToolPolicy): string;
export declare const claudeCLISpec: AgentCLISpec;
/**
* CLIs conhecidos são listados para diagnóstico e roteamento honesto. A
* presença do binário não autoriza um adapter inventado: até existir um
* contrato de stdout/flags testado, o estado permanece unsupported.
*/
export declare const KNOWN_AGENT_CLI_SPECS: AgentCLISpec[];
/** Specs conhecidos, por id de provider. */
export declare const AGENT_CLI_SPECS: Record;
/** Ids de providers com adapter real; entram no runtime e no roteamento. */
export declare const AGENT_CLI_PROVIDERS: string[];
/** Ids conhecidos apenas para diagnóstico de instalação/capability. */
export declare const KNOWN_AGENT_CLI_PROVIDERS: string[];
/** CLIs realmente executáveis e disponíveis, em ordem configurável. */
export declare function availableAgentCLIProviders(env?: NodeJS.ProcessEnv): string[];
export interface SpawnResult {
stdout: string;
stderr: string;
code: number | null;
timedOut: boolean;
aborted: boolean;
}
/** Executa o binário com argv em array (sem shell) e stdin fechado ao fim. */
export declare function runAgentCLI(bin: string, args: string[], stdin: string, opts: {
cwd?: string;
timeoutMs: number;
signal?: AbortSignal;
env?: NodeJS.ProcessEnv;
}): Promise;
/**
* Adapter de um CLI de agente. Implementa `ModelAdapter`, então entra no
* `LLMClient` como qualquer provider e atravessa run/SDK/models/juiz/arena sem
* que nenhum chamador mude.
*/
export declare class AgentCLIAdapter implements ModelAdapter {
readonly provider: string;
private readonly spec;
private readonly env;
private readonly cwd;
private resolvedBin;
constructor(spec: AgentCLISpec, opts?: {
env?: NodeJS.ProcessEnv;
cwd?: string;
});
/** Caminho absoluto do binário, memoizado (`null` = não está no PATH). */
get binPath(): string | null;
/**
* `true` quando o binário existe, o adapter não foi desligado e a
* profundidade de recursão ainda cabe.
*
* Não verifica autenticação: não existe checagem barata e offline disso, e
* spawnar o agente só para perguntar "você está logado?" custaria uma
* chamada de modelo por run. Falha de auth aparece como erro real do CLI na
* primeira chamada, com o stderr dele na mensagem.
*/
get configured(): boolean;
/** Motivo de não estar utilizável, para mensagem ao usuário. `null` = utilizável. */
get unavailableReason(): string | null;
complete(opts: CompletionOptions): Promise;
}
/** Adapters de CLI de agente conhecidos, prontos para o `LLMClient`. */
export declare function defaultAgentCLIAdapters(opts?: {
env?: NodeJS.ProcessEnv;
cwd?: string;
}): AgentCLIAdapter[];
/**
* Diagnóstico dos executores sem chave, para `izanagi doctor`/`models`.
* Determinístico e offline: só olha PATH, env e profundidade.
*/
export declare function agentCLIStatus(env?: NodeJS.ProcessEnv): Array<{
provider: string;
label: string;
bin: string;
path: string | null;
available: boolean;
reason: string | null;
install: string;
}>;
/**
* Diretório temporário do adapter. Existe para os specs que precisarem de
* arquivo auxiliar; o spec do Claude não precisa (tudo vai por stdin/argv).
*/
export declare function tempDir(): string;
//# sourceMappingURL=agent-cli.d.ts.map