/** * QwenAgentRunner — AgentRunner impl backed by the Qwen Code CLI (`qwen`, * https://qwenlm.github.io/qwen-code-docs/). * * Architectural pattern: SAME as CodexAgentRunner/GrokAgentRunner — spawn the * vendor's CLI binary, parse its stream-json output, normalize to * AgentMessage. No SDK dependency. * * Auth: inherited from the CLI's own login flow. No env vars set here. * * Streaming / liveness — WHY INCREMENTAL (#204): * This runner originally buffered ALL of qwen's stdout until the subprocess * exited before parsing anything, so any turn longer than session.ts's * 4-minute silent-stream watchdog (SILENT_SESSION_MS) yielded zero messages * in time — abort, retry, kill, circuit breaker. Same bug class as the * kimi/antigravity/codex runners had (#204 audit). This runner now parses * stdout LINE BY LINE as it arrives: a liveness `tool_use` message is * yielded the moment the subprocess spawns (deterministically winning the * first-pull race regardless of model-thinking latency), and each * `assistant` event's text is yielded as its line lands (qwen's * stream-json sends whole messages per event, not per-token deltas — * confirmed live, #182 — so no accumulation is needed, unlike agy). * Tool_call fences are still collected from the raw texts and parsed at * end of turn (fence parsing needs the complete text). * * Org tools — FENCE PROTOCOL: same approach as the other subprocess runners * (see tool-fence.ts). * * Subprocess protocol — LIVE-VERIFIED against qwen-code v0.21.13 (issue * #182 investigation; z.ai/GLM-5.3 as the OpenAI-compatible backend, `qwen * --auth-type openai` + `OPENAI_API_KEY`/`OPENAI_BASE_URL`/`OPENAI_MODEL`): * - Invocation: `qwen -p "" --output-format stream-json --yolo * [-m ] [--resume | --continue]` * - stream-json emits one JSON object per line; CONFIRMED shape (the * public docs' `usage.tokens.{input,output}` nesting does NOT match * live output — real usage fields are flat): * { type: 'system'|'assistant'|'result', subtype, uuid, session_id, * role: 'assistant', * message: { content: [{type:'text', text}], * usage: { input_tokens, output_tokens, cache_read_input_tokens, total_tokens } } } * - Session continuity: `--resume [sessionId]` resumes a specific session, * `--continue` resumes the most recent one; `session_id` is carried on * every event. * - `--yolo` auto-approves tool actions (org roles gate tool execution * themselves via canUseTool/tool-fence, so CLI-level approval prompts * would otherwise hang a non-interactive run). * - Native tools: qwen-code's headless adapter writes Claude-compatible * frames — `tool_use` blocks in assistant messages and `tool_result` * blocks (with `is_error`) in `user` messages, correlated by the call * id (read from the qwen-code 0.x bundle, not a live run). They are * forwarded as rich tool_use/tool_result pairs. * * File-size sweep: the wire types + event parser (handleQwenEvent, * parseQwenEvents) live in qwen-runner-parse.ts, and the subprocess turn * runner (streamTurn) and turn-error builder (turnError) live in * qwen-runner-stream.ts — both re-exported below where other modules import * them from here. */ import type { AgentMessage, AgentRunArgs, AgentRunner } from './agent-runner.js'; export type { QwenStreamEvent } from './qwen-runner-parse.js'; export { parseQwenEvents } from './qwen-runner-parse.js'; export declare class QwenAgentRunner implements AgentRunner { private qwenBin?; constructor(qwenBin?: string | undefined); run(args: AgentRunArgs): AsyncIterable; } //# sourceMappingURL=qwen-runner.d.ts.map