/** * QwenRpcAgentRunner — AgentRunner impl backed by the Qwen Code CLI's * bidirectional `--input-format stream-json --output-format stream-json` * mode (session-lifetime), instead of the default QwenAgentRunner * (qwen-runner.ts), which spawns a fresh `qwen -p ""` process per * mailbox turn. * * OPT-IN, not the default. Select via role/org `runtime: 'qwen-rpc'`. * Prefer plain `runtime: 'qwen'` (QwenAgentRunner) unless you specifically * want the benefit this buys: the subprocess stays alive for the WHOLE * mailbox session, so conversational context carries naturally (no * `--resume ` round-trip per turn) and there's no per-turn * spawn/bootstrap cost. * * Protocol — LIVE-VERIFIED against qwen-code v0.21.13 (issue #182). The * flag exists but is hidden from `qwen --help`; found by reading the * bundled minified source (`packages/cli`'s yargs config, * `.option("input-format", { choices: ["text","stream-json"] })`) and * confirmed the exact message schema from the CLI's own bundled source * (`packages/cli/src/nonInteractive/types.ts`, compiled into * `chunks/session-*.js`) — the `isCLIUserMessage`/`extractUserMessageText` * predicates there define the client→server shape literally, not from * prose docs. Then confirmed LIVE: sent both message forms below on the * same persistent subprocess against a z.ai/GLM-5.3 backend — both * answered correctly, on the SAME session_id, proving session-lifetime * persistence: * * Client → server (this runner sends): * {"type":"user","message":{"content":""}} * (a content-block-array form is also accepted — * {"type":"user","message":{"content":[{"type":"text","text":"..."}]}} * — but the plain-string form is simpler and was used for all live * verification, so this runner sticks to it) * * Server → client (same vocabulary as QwenAgentRunner's per-spawn * stream-json, confirmed identical live under RPC mode too): * {"type":"system","subtype":"init","session_id":"...",...} * {"type":"assistant","session_id":"...", * "message":{"content":[{"type":"text","text":"..."}, * {"type":"thinking","thinking":"..."}]}} * {"type":"result","subtype":"success"|"error","session_id":"...", * "usage":{"input_tokens":N,"output_tokens":N,...}, * "error":{"message":"..."}|""} * `result` is a single-fire-per-turn completion signal — confirmed live * (same as the non-RPC QwenAgentRunner already relies on for its * per-spawn invocations). A `system`/`init` event was also observed * re-emitted at the start of a SECOND turn on the same subprocess — not * treated as a new-session signal here, since session_id stayed * identical across it in the live test. * * NOT verified live: a turn where qwen runs multiple of its OWN native * tools (read/edit/bash) in sequence before responding — same class of gap * pi-rpc-runner.ts disclosed for pi before its own live verification * confirmed a single fire-once completion signal there too. `result` * firing exactly once per submitted `user` message (not once per internal * tool-use cycle) is inferred by symmetry with the non-RPC QwenAgentRunner * (which already treats `result` this way across a `-p` invocation that * CAN involve multiple internal tool calls) rather than independently * re-confirmed here. Revalidate if this runner ends a turn early or hangs * on a heavily tool-call-heavy prompt; fall back to plain `runtime: 'qwen'` * if it misbehaves. * * Auth: inherited from the CLI's own login flow — same as QwenAgentRunner. * No env vars set here. (Live verification against a custom * OpenAI-compatible backend needed `--auth-type openai` plus * `OPENAI_API_KEY`/`OPENAI_BASE_URL`/`OPENAI_MODEL` env vars, per * qwen-runner.ts's own header — not something this runner forces, since a * real deployment's own qwen config/subscription should already be set up * the way its operator wants.) * * Org tools (org_send, knowledge_search, ask_human, …) — FENCE PROTOCOL: * Qwen's own native tools (read/edit/bash) execute autonomously inside * qwen itself and never reach this runner — only org tools ride the * shared tool-fence protocol (tool-fence.ts), extracted from assistant * text collected before `result` and fed back as a new `user` message in * the SAME session. */ import { type AgentMessage, type AgentRunArgs, type AgentRunner } from './agent-runner.js'; import { type SpawnQwenRpc } from './qwen-rpc-runner-helpers.js'; export type { QwenRpcProcess, SpawnQwenRpc } from './qwen-rpc-runner-helpers.js'; export { encodeQwenRpcUserMessage, extractQwenRpcText, QwenJsonlDecoder, } from './qwen-rpc-runner-helpers.js'; export declare class QwenRpcAgentRunner implements AgentRunner { private qwenBin?; private spawnFn; constructor(qwenBin?: string | undefined, spawnFn?: SpawnQwenRpc); run(args: AgentRunArgs): AsyncIterable; } //# sourceMappingURL=qwen-rpc-runner.d.ts.map