Skip to content

feat(agents): add Qwen Coder (qwen3-coder) and Oh My Pi (omp) agents#1138

Open
jSydorowicz21 wants to merge 13 commits into
rcfrom
feat/qwen-omp-agents
Open

feat(agents): add Qwen Coder (qwen3-coder) and Oh My Pi (omp) agents#1138
jSydorowicz21 wants to merge 13 commits into
rcfrom
feat/qwen-omp-agents

Conversation

@jSydorowicz21

@jSydorowicz21 jSydorowicz21 commented Jun 27, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #803.

Bundles the two new CLI agents into a single PR. They were previously split across #1128 (Qwen Coder) and #1132 (Oh My Pi), but each adds an agent to the same shared registry files, so they cannot merge independently without conflicts (parser registry, agent metadata/constants, error patterns, the supported-agents list, and the "register exactly N parsers" count). Combining them here resolves that once: both agents registered, parser count is 8.

This supersedes and replaces #1128 and #1132.

Qwen Coder (qwen3-coder)

  • Promotes the hidden qwen3-coder stub to a real, selectable BETA agent (binary qwen), mirroring the gemini-cli integration: definition, capabilities, metadata, 256K context window, QwenOutputParser, error patterns, --output-format stream-json, --resume.
  • Model selector is a free-text field (qwen-code's -m/--model is an unconstrained, multi-provider string per its source; a fixed dropdown would exclude valid models).

Oh My Pi (omp)

  • Adds omp (@oh-my-pi/pi-coding-agent) as a real, selectable BETA agent registered everywhere gemini-cli is: definition, capabilities, metadata, OmpOutputParser (modeled on the sibling pi-output-parser), error patterns, -p --mode json, --resume, --model.
  • Model selector is free-text, and runModelDiscovery runs omp models --json to populate the model combobox with omp's full multi-provider catalog (provider-qualified selectors, de-duplicated, parsed with parseJsonWithBom).

Verification

  • npm run lint (tsc x3): clean.
  • vitest run across parsers/index, agent definitions, agent-completeness, agentMetadata, detector (incl. omp discovery), capabilities: 252 tests pass.
  • eslint + prettier: clean on the touched files.

Notes

  • Conflicts were resolved as a union of both agents; the parser-count assertion is set to 8 (6 base + qwen + omp).
  • Independently exercised in a local integration build (both agents appear in New Instance; omp model picker populates).

Summary by CodeRabbit

  • New Features
    • Added support for two additional AI coding agents: qwen3-coder and omp (beta), including UI display name/icon, agent setup, model discovery, and output parsing with session + streaming + usage/cost handling.
    • Added agent-specific error pattern handling for both agents, plus remote model discovery JSON parsing.
  • Bug Fixes
    • Improved result/error/session classification for the new parsers.
    • Prevented caching empty model discovery results for omp to allow retries.
  • Documentation
    • Updated README to include the expanded multi-agent support and requirements.

Promotes the hidden qwen3-coder stub to a real, selectable BETA agent mirroring gemini-cli: stream-json output, --resume, and model-arg selection. Adds a registered QwenOutputParser, Qwen error patterns, NewInstanceModal entry, capabilities, context window, and README. Covered by parser + definition + capabilities + metadata tests; agent-completeness passes.
Adds omp (Oh My Pi, @oh-my-pi/pi-coding-agent) as a real, selectable BETA agent registered everywhere gemini-cli is. Spawns non-interactively as 'omp -p --mode json' with --resume and --model; new custom OmpOutputParser handles omp's JSON event stream (session/message_update[text_delta]/message_end[usage+cost]/agent_end), modeled on the sibling Pi parser. Includes capabilities, error patterns, path discovery, NewInstanceModal entry, README, and tests (parser fixture, definitions, capabilities, metadata, ids); agent-completeness passes.
…803)

CI full suite caught that parsers/index.test.ts hardcodes the registered-parser count, which the new QwenOutputParser bumped 6 -> 7. Update the count assertions + title and add a 'should register Qwen parser' test mirroring the Pi one.
Review fixes: set supportsImageInput=false (no image args wired, attachments would be dropped); set supportsResume=true to match the wired --resume args; honor Qwen's is_error:true in QwenOutputParser (reclassify failed results to error events + emit structured AgentError); add a session_not_found error pattern for expired --resume sessions. Deferred plan-mode read-only (matches gemini convention) and native --append-system-prompt (Windows file-variant unverified). Tests updated.
…(#omp)

Review fixes for the Oh My Pi agent: drop noPromptSeparator so omp uses Maestro's '--' end-of-options separator (verified omp supports it), protecting flag-like prompts while keeping @image args before the separator; add noToolsArgs ['--no-tools'] so tab-naming launches name-only (mirrors Pi); make OmpOutputParser fall back to assembled streamed text when agent_end has no/empty messages. Declined --append-system-prompt (Windows uses --append-system-prompt-file which omp lacks; cross-cutting) and model free-text (SELECT matches gemini/qwen convention); deferred read-only allowlist.
Round-2 review fixes: strip the inherited Claude 200000 fallback contextWindow from Qwen usage so the spawned process's configured 262144 window drives the context meter/summarization (genuinely larger reported windows are preserved); populate is_error result text from Qwen's error.message so failed runs surface the actionable provider message instead of an empty/generic error. Declined the stdin prompt-flag finding: per qwen-code source, piped child spawns are non-interactive (stdin.isTTY=false) and read stdin as the prompt, so adding -p would duplicate it and forcing it as an arg reintroduces the cmd.exe arg-length limit the stdin path avoids. +4 tests.
…fixed dropdown

omp --model is fuzzy and multi-provider (opus, gpt-5.2, openai/gpt-5.2, ollama/..., 20+ providers). The hardcoded 6-item select (incl. stale gpt-5) couldn't represent that; switched to type:'text' matching its sibling pi/hermes/opencode/codex agents.
…pdown

qwen-code's -m/--model is declared type:'string' with no choices enum and is an unconstrained pass-through for all non-OAuth auth types (API-key/third-party). It's multi-provider (OpenAI/Anthropic/Gemini/Vertex/OpenRouter/vLLM/Ollama). The hardcoded 5-item select omitted the actual default (coder-model) and the entire multi-provider space; switched to type:'text' like omp/codex/opencode. Test updated.
Adds an omp case to runModelDiscovery so the model combobox lists omp's full multi-provider catalog (provider-qualified selectors, de-duplicated). Without it the picker showed no models. Mirrors the OpenCode discovery pattern; parseJsonWithBom for robustness.
# Conflicts:
#	README.md
#	src/__tests__/main/parsers/index.test.ts
#	src/__tests__/shared/agentMetadata.test.ts
#	src/main/parsers/error-patterns.ts
#	src/main/parsers/index.ts
#	src/main/parsers/parser-factory.ts
#	src/renderer/components/NewInstanceModal/types.ts
#	src/shared/agentConstants.ts
#	src/shared/agentMetadata.ts
@coderabbitai

coderabbitai Bot commented Jun 27, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 27b14150-d24e-4701-94da-5b398adc546b

📥 Commits

Reviewing files that changed from the base of the PR and between a24a058 and 3ad50cd.

📒 Files selected for processing (6)
  • src/__tests__/main/agents/capabilities.test.ts
  • src/__tests__/main/agents/definitions.test.ts
  • src/__tests__/main/utils/agent-args.test.ts
  • src/main/agents/capabilities.ts
  • src/main/agents/definitions.ts
  • src/main/ipc/handlers/agents.ts
✅ Files skipped from review due to trivial changes (1)
  • src/tests/main/utils/agent-args.test.ts
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/tests/main/agents/capabilities.test.ts
  • src/main/agents/capabilities.ts
  • src/tests/main/agents/definitions.test.ts
  • src/main/agents/definitions.ts
  • src/main/ipc/handlers/agents.ts

📝 Walkthrough

Walkthrough

Adds support for qwen3-coder and omp across shared metadata, agent wiring, parsers, discovery, renderer support, tests, and README text.

Changes

qwen3-coder and omp agent integration

Layer / File(s) Summary
Shared IDs and metadata
src/shared/agentIds.ts, src/shared/agentMetadata.ts, src/shared/agentConstants.ts, src/renderer/components/NewInstanceModal/types.ts, src/renderer/constants/agentIcons.ts, README.md
Adds omp to agent IDs and display names, marks qwen3-coder and omp as beta agents, extends the qwen3-coder default context window, updates the supported-agent list, maps omp to an icon, and updates the README agent lists and requirements text.
Agent definitions and discovery
src/main/agents/definitions.ts, src/main/agents/capabilities.ts, src/main/agents/detector.ts, src/main/agents/path-prober.ts, src/main/ipc/handlers/agents.ts, src/main/parsers/error-patterns.ts
Updates qwen3-coder and omp agent definitions and capabilities, adds omp path probing, implements omp model discovery with empty-result retry behavior, changes remote model discovery for omp over SSH, and registers qwen3-coder/omp error patterns.
Output parsers
src/main/parsers/qwen-output-parser.ts, src/main/parsers/omp-output-parser.ts, src/main/parsers/index.ts, src/main/parsers/parser-factory.ts
Adds QwenOutputParser and OmpOutputParser, registers both in the parser index and factory, and wires their event parsing and error classification behavior.
Parser and agent tests
src/__tests__/main/agents/*, src/__tests__/main/parsers/*, src/__tests__/main/ipc/handlers/agents.test.ts, src/__tests__/main/utils/agent-args.test.ts, src/__tests__/shared/*
Extends capability, definition, detector, metadata, parser index, qwen parser, omp parser, IPC remote-model, and argument-building tests for the new agent support.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

  • RunMaestro/Maestro#546: Adds adjacent agent-registration and parser-support changes on the same shared surfaces updated here.
  • RunMaestro/Maestro#1032: Extends the same agent framework with new definitions and argument-building coverage.
  • RunMaestro/Maestro#538: Touches parser/event-handling logic similar to the new Qwen and Omp output parsers.

Suggested labels

ready to merge

Poem

🐰 Two new agents hop in line,
Qwen and Omp both parse just fine.
JSON streams and model picks,
Owl icons and CLI tricks.
Carrots cheer, the bundle glows,
And every registry now knows.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Out of Scope Changes check ⚠️ Warning The Oh My Pi agent additions are unrelated to linked issue #803, which only requested Qwen Coder support. Split the Oh My Pi work into a separate PR or link a matching issue so this PR stays scoped to #803.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding Qwen Coder and Oh My Pi agent support.
Linked Issues check ✅ Passed The PR adds Qwen Coder support with selectable model configuration and matches the linked issue's integration pattern.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/qwen-omp-agents

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jun 27, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds Qwen3 Coder and Oh My Pi as beta agents. The main changes are:

  • New agent definitions, capabilities, metadata, icons, and context-window defaults.
  • Parser registration plus new Qwen and Oh My Pi output parsers.
  • Oh My Pi model discovery through omp models --json.
  • Tests and README updates for the new agents.

Confidence Score: 5/5

This looks safe to merge after a small model-discovery cache cleanup.

  • The parser and spawn definitions match the existing Gemini and Pi integration patterns.
  • The only issue found is limited to stale empty model suggestions after a temporary Oh My Pi discovery failure.
  • Core agent execution, parser registration, and shared metadata look complete.

src/main/agents/detector.ts

Important Files Changed

Filename Overview
src/main/agents/definitions.ts Adds visible Qwen and Oh My Pi agent definitions with spawn flags, model options, and context-window settings.
src/main/agents/capabilities.ts Updates Qwen capabilities and adds Oh My Pi streaming, model, usage, cost, and resume capability flags.
src/main/agents/detector.ts Adds Oh My Pi model discovery, with a small cache behavior issue on transient discovery failures.
src/main/parsers/qwen-output-parser.ts Adds a Qwen stream-json parser that reuses Claude parsing and handles Qwen failed-result events.
src/main/parsers/omp-output-parser.ts Adds an Oh My Pi JSON event parser for sessions, streaming text, usage, final results, tools, and errors.
src/main/parsers/index.ts Registers and exports the new parser classes.
src/main/parsers/parser-factory.ts Adds factory entries for Qwen and Oh My Pi parsers.
src/main/parsers/error-patterns.ts Adds Qwen and Oh My Pi error pattern registries.
src/shared/agentIds.ts Adds Oh My Pi to the shared agent id list.
src/shared/agentMetadata.ts Adds Oh My Pi display metadata and marks both new visible agents as beta.
src/shared/agentConstants.ts Adds context-window defaults for Qwen and Oh My Pi.
src/main/agents/path-prober.ts Adds standard known install paths for the omp binary.
src/renderer/components/NewInstanceModal/types.ts Adds Qwen and Oh My Pi to the new-agent selector list.
src/renderer/constants/agentIcons.ts Adds an icon entry for Oh My Pi.
README.md Documents Qwen3 Coder and Oh My Pi as supported beta agents.

Reviews (1): Last reviewed commit: "Merge branch 'feat/omp-agent' into feat/..." | Re-trigger Greptile

LOG_CONTEXT,
{ stderr: result.stderr }
);
return [];

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Transient Failure Stays Cached

When omp models --json fails once, this branch returns an empty list and the caller caches that result under the omp agent key for the normal model-cache window. A temporary CLI or parse failure can make the model picker stay empty for later successful retries until the cache expires or is manually cleared.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/__tests__/main/agents/definitions.test.ts (1)

172-181: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Include qwen3-coder in the “all known agents” list.

This list was updated for omp, but it still skips the other agent added in this PR, so this regression test would not catch getAgentDefinition('qwen3-coder') returning undefined.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/__tests__/main/agents/definitions.test.ts` around lines 172 - 181, The
regression test in definitions.test.ts is missing the newly added agent in its
knownAgents list, so update the “should return definition for all known agents”
case to include qwen3-coder alongside the existing entries. Keep the change
localized to the knownAgents array in the getAgentDefinition coverage so the
test will fail if qwen3-coder is not registered.
🧹 Nitpick comments (2)
src/__tests__/main/parsers/index.test.ts (1)

149-153: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add the same class/export assertions for Qwen.

This suite now fully exercises OMP, but qwen3-coder is only checked via hasOutputParser(). Adding getOutputParser('qwen3-coder') and new QwenOutputParser().agentId assertions would cover the new re-export and keep both agents symmetric in this layer.

Also applies to: 182-185

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/__tests__/main/parsers/index.test.ts` around lines 149 - 153, The parser
tests for qwen3-coder only verify hasOutputParser(), so add matching coverage in
the getOutputParser and class/export assertions used for OMP. Update the
index.test.ts cases around getOutputParser and the Qwen re-export to call
getOutputParser('qwen3-coder') and assert it returns a QwenOutputParser
instance, and also verify new QwenOutputParser().agentId matches the expected
agent id so the symmetry with OmpOutputParser is covered.
src/main/parsers/omp-output-parser.ts (1)

22-22: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use the shared ANSI stripping helper here.

This introduces a separate ANSI-stripping path in src/**. Please switch both the import and call site to stripAnsiCodes() from src/shared/stringUtils.ts so this stays aligned with the shared utility contract.

Suggested change
-import { stripAllAnsiCodes } from '../utils/terminalFilter';
+import { stripAnsiCodes } from '../../shared/stringUtils';
...
-		const cleanedOutput = stripAllAnsiCodes(`${stderr}\n${stdout}`).trim();
+		const cleanedOutput = stripAnsiCodes(`${stderr}\n${stdout}`).trim();

As per coding guidelines, "Use stripAnsiCodes() from src/shared/stringUtils.ts for removing ANSI escape codes. Do not create duplicate implementations."

Also applies to: 267-267

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/main/parsers/omp-output-parser.ts` at line 22, The ANSI stripping logic
in the parser is using a local helper instead of the shared utility. Update
src/main/parsers/omp-output-parser.ts to import stripAnsiCodes from
src/shared/stringUtils.ts and replace every stripAllAnsiCodes call in this
parser with stripAnsiCodes so the parser follows the shared contract and avoids
a duplicate ANSI-removal path.

Source: Coding guidelines

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/__tests__/main/parsers/omp-output-parser.test.ts`:
- Around line 6-20: The OMP parser fixture currently embeds a real local Windows
user path in OMP_SAMPLE, which leaks a developer identifier. Update the captured
JSONL sample in omp-output-parser.test.ts to use a sanitized placeholder path
instead of the concrete C:\\Users\\sydor\\... value, while keeping the rest of
the parser coverage data unchanged.

In `@src/main/parsers/omp-output-parser.ts`:
- Around line 98-105: The OMP parser is treating retrying agent_end events with
error payloads as final failures; update OmpOutputParser so willRetry-marked
events are filtered out before any error short-circuit in both the parse flow
and detectErrorFromParsed logic. Adjust the agent_end handling in the parser
methods that inspect event.error/event.message?.errorMessage and the willRetry
guard so they return a non-fatal path when willRetry is true, then add a
regression test covering agent_end with willRetry true plus error text to ensure
it is not surfaced as a user-facing error.

In `@src/main/parsers/qwen-output-parser.ts`:
- Around line 55-67: The Qwen output parser is deleting any usage.contextWindow
equal to the fallback value, which can նաև remove a legitimate 200000 limit from
real model payloads. Update qwen-output-parser’s event handling so the fallback
is stripped only when the original payload did not report a context window,
using the existing usage normalization path in
QwenOutputParser/aggregateModelUsage. Add a regression test covering an exact
200000 Qwen-reported context window to ensure it is preserved.

---

Outside diff comments:
In `@src/__tests__/main/agents/definitions.test.ts`:
- Around line 172-181: The regression test in definitions.test.ts is missing the
newly added agent in its knownAgents list, so update the “should return
definition for all known agents” case to include qwen3-coder alongside the
existing entries. Keep the change localized to the knownAgents array in the
getAgentDefinition coverage so the test will fail if qwen3-coder is not
registered.

---

Nitpick comments:
In `@src/__tests__/main/parsers/index.test.ts`:
- Around line 149-153: The parser tests for qwen3-coder only verify
hasOutputParser(), so add matching coverage in the getOutputParser and
class/export assertions used for OMP. Update the index.test.ts cases around
getOutputParser and the Qwen re-export to call getOutputParser('qwen3-coder')
and assert it returns a QwenOutputParser instance, and also verify new
QwenOutputParser().agentId matches the expected agent id so the symmetry with
OmpOutputParser is covered.

In `@src/main/parsers/omp-output-parser.ts`:
- Line 22: The ANSI stripping logic in the parser is using a local helper
instead of the shared utility. Update src/main/parsers/omp-output-parser.ts to
import stripAnsiCodes from src/shared/stringUtils.ts and replace every
stripAllAnsiCodes call in this parser with stripAnsiCodes so the parser follows
the shared contract and avoids a duplicate ANSI-removal path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 4c666217-ec3a-4f83-8679-3f4e8b8a9d46

📥 Commits

Reviewing files that changed from the base of the PR and between b330223 and 10efc4f.

📒 Files selected for processing (23)
  • README.md
  • src/__tests__/main/agents/capabilities.test.ts
  • src/__tests__/main/agents/definitions.test.ts
  • src/__tests__/main/agents/detector.test.ts
  • src/__tests__/main/parsers/index.test.ts
  • src/__tests__/main/parsers/omp-output-parser.test.ts
  • src/__tests__/main/parsers/qwen-output-parser.test.ts
  • src/__tests__/shared/agentIds.test.ts
  • src/__tests__/shared/agentMetadata.test.ts
  • src/main/agents/capabilities.ts
  • src/main/agents/definitions.ts
  • src/main/agents/detector.ts
  • src/main/agents/path-prober.ts
  • src/main/parsers/error-patterns.ts
  • src/main/parsers/index.ts
  • src/main/parsers/omp-output-parser.ts
  • src/main/parsers/parser-factory.ts
  • src/main/parsers/qwen-output-parser.ts
  • src/renderer/components/NewInstanceModal/types.ts
  • src/renderer/constants/agentIcons.ts
  • src/shared/agentConstants.ts
  • src/shared/agentIds.ts
  • src/shared/agentMetadata.ts

Comment thread src/__tests__/main/parsers/omp-output-parser.test.ts
Comment thread src/main/agents/detector.ts
Comment thread src/main/parsers/omp-output-parser.ts Outdated
Comment thread src/main/parsers/qwen-output-parser.ts Outdated
- omp discovery: don't cache transient empty results so a failed 'omp models --json' doesn't leave the picker empty for the TTL (greptile P2); report parse failures via captureException (CodeRabbit).
- omp parser: suppress willRetry-marked agent_end events in both parseJsonObject and detectErrorFromParsed so retrying turns aren't surfaced as final errors (CodeRabbit major) + regression test.
- omp parser: use shared stripAnsiCodes() from shared/stringUtils instead of a duplicate path (CodeRabbit).
- omp test fixture: redact local username from the captured sample path (CodeRabbit security).
- qwen parser: only strip the injected 200000 fallback when the raw payload reported no per-model context window; preserve a genuinely model-reported 200000 (CodeRabbit) + regression test.
- tests: add qwen3-coder to definitions knownAgents; add getOutputParser/export symmetry for qwen; add detector cache-retry regression test.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 10efc4f3e8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/main/parsers/qwen-output-parser.ts Outdated
Comment on lines +63 to +65
if (event.usage && event.usage.contextWindow === FALLBACK_CONTEXT_WINDOW) {
const usage = { ...event.usage };
delete usage.contextWindow;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve real Qwen context windows at 200K or below

When a Qwen agent uses the multi-provider model override, for example the OpenAI-compatible models allowed in definitions.ts:375, a real reported context window of 200000 or lower is collapsed to the Claude fallback by aggregateModelUsage and then removed here. StdoutHandler.buildUsageStats will fall back to the Qwen default/configured 262144 window, so context usage and compaction thresholds are too high for those models. Please distinguish "no context window was reported" from "the provider reported 200000 or a lower value" before deleting the field.

Useful? React with 👍 / 👎.

args: [],
batchModePrefix: [],
batchModeArgs: ['-y'],
jsonOutputArgs: ['--output-format', 'stream-json'],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Include Qwen partial stream events

For Qwen runs this only requests --output-format stream-json, but the Qwen CLI docs say partial assistant events require --include-partial-messages and that it defaults off. In normal Maestro tabs that means Qwen is marked streaming/thinking-capable, yet the parser only gets the terminal result instead of live assistant/reasoning deltas, so users see no response content until exit and the Thought Stream cannot populate. Add the partial flag or lower the streaming/thinking capabilities.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Confirmed valid against qwen-code v0.19.2 source: --output-format stream-json alone emits only the final complete assistant message plus result, and --include-partial-messages (default off) is required for live text/thinking deltas.

Decision for this PR: leaving it as-is. The behavior is functional today, qwen's full response still renders (the parser treats the final assistant message as partial text), just at turn-end rather than token-by-token.

We are not enabling --include-partial-messages here because qwen emits partials as Anthropic-style stream_event envelopes (event.type: content_block_delta, delta.type: text_delta/thinking_delta) that ClaudeOutputParser does not currently parse, and they arrive alongside the final complete message, so flipping the flag without new parser handling and de-duplication would double-render the response.

Live token/thinking streaming for qwen is tracked as a follow-up (add the flag plus a stream_event handler in QwenOutputParser and dedupe the final message), to be done against a live qwen CLI so the envelope shape and ordering can be validated.

requiresPromptToStart: true,
supportsStreaming: true,
supportsResultMessages: true,
supportsModelSelection: true,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Handle OMP model discovery over SSH

Declaring OMP model selection here also enables the SSH remote model picker, but discoverModelsRemote always runs <binary> models and splits stdout by line. The local OMP branch added in this commit has to run omp models --json and read models[].selector; on SSH remotes the picker will be filled with human table headings/box rows, and selecting one sends an invalid --model. Add an OMP-specific remote discovery path or avoid advertising model selection for remote OMP agents.

Useful? React with 👍 / 👎.

Comment on lines +136 to +140
if (event.message?.role === 'assistant') {
return {
type: 'usage',
sessionId,
usage: this.extractUsageFromMessage(event.message),

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Deduplicate repeated OMP usage messages

The captured OMP sample in the new test fixture includes two assistant message_end events carrying the same usage for one turn, but this parser emits a usage event for every assistant message_end. For OMP, StdoutHandler forwards each usage event as a delta and the renderer accumulates those deltas, so one OMP response can double-count tokens and cost in the session totals and Usage Dashboard. Gate this to the authoritative final usage per message or de-duplicate repeated usage payloads.

Useful? React with 👍 / 👎.

…overy)

- qwen parser (C1): aggregateModelUsage only overrides the 200000 fallback with a LARGER per-model window, so a model reporting <=200000 (e.g. a custom OpenAI-compatible model) was collapsed to 200000. Now recover the real value from raw modelUsage (largest reported >0) and only strip the injected fallback when no window was reported. +2 tests (200000 and 128000 reported windows preserved).
- omp SSH discovery (C3): discoverModelsRemote ran '<binary> models' and split stdout by line; for omp that yields the human table, so the remote picker filled with headings and produced invalid --model. Now request 'omp models --json' and parse selectors for omp, mirroring local discovery. +1 IPC test.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/main/ipc/handlers/agents.ts`:
- Around line 650-681: The remote `omp` JSON branch in `agents.ts` is parsing
raw `result.stdout`, so any ANSI or shell noise can make `parseJsonWithBom()`
fail and cache an empty model list. Normalize the SSH output first by stripping
ANSI escape codes with `stripAnsiCodes()` before parsing, and use the cleaned
stdout consistently in the `agentId === 'omp'` path and the non-JSON fallback so
model discovery stays reliable.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2007d45a-2dd4-47cb-9cd0-812a02212ee5

📥 Commits

Reviewing files that changed from the base of the PR and between b18fa73 and a24a058.

📒 Files selected for processing (4)
  • src/__tests__/main/ipc/handlers/agents.test.ts
  • src/__tests__/main/parsers/qwen-output-parser.test.ts
  • src/main/ipc/handlers/agents.ts
  • src/main/parsers/qwen-output-parser.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/tests/main/parsers/qwen-output-parser.test.ts
  • src/main/parsers/qwen-output-parser.ts

Comment thread src/main/ipc/handlers/agents.ts

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: a24a058344

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

workingDirArgs: (dir: string) => ['--include-directories', dir],
imageArgs: undefined,
modelArgs: (modelId: string) => ['-m', modelId],
promptArgs: (prompt: string) => ['-p', prompt],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add Qwen's prompt flag for SSH stdin runs

When a Qwen agent runs on an SSH remote, the SSH path in src/main/ipc/handlers/process.ts builds the remote command from finalArgs and sends effectivePrompt as stdinInput, so this promptArgs builder is not applied. That yields qwen -y --output-format stream-json with the prompt on stdin but no --prompt/-p; Qwen's CLI docs show stdin piping as echo ... | qwen --prompt and stream JSON as qwen --prompt ... --output-format stream-json (https://qwenlm-qwen-code.mintlify.app/cli/overview). In that context the remote process can enter interactive mode or fail instead of producing JSON, so Qwen SSH tabs and batch runs do not complete.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Verified against qwen-code v0.19.2 source: this is a non-issue. qwen reads a piped (non-TTY) stdin as the prompt automatically; --prompt/-p is additive, not required (description: 'Prompt. Appended to input on stdin (if any).', config.ts:642). With no prompt flag and a non-TTY stdin, it runs non-interactively (interactive = process.stdin.isTTY ?? false, config.ts:1528-1532) and folds stdin into the prompt (gemini.tsx:967-972).

The one caveat is that stdin is consumed as the plain prompt only while --input-format is text (the default); --input-format stream-json would reserve stdin for the JSON protocol. Maestro passes --output-format stream-json but NOT --input-format stream-json, so the SSH stdin-as-prompt path is correct. No -p added.

Comment thread src/main/agents/definitions.ts Outdated
// Qwen Code is a Gemini CLI fork; read-only behavior is enforced via system prompt
// instructions. The -y flag is still needed for non-interactive execution to prevent
// approval prompts from hanging batch mode.
readOnlyArgs: ['-y'],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Use Qwen plan mode for read-only spawns

When maestro-cli send --read-only or any non-UI caller sets readOnlyMode for a Qwen agent, the definition appends -y, which Qwen documents as YOLO auto-approval, while --approval-mode plan is the mode that analyzes without modifying files or executing commands (https://raw.githubusercontent.com/QwenLM/qwen-code/main/docs/users/configuration/settings.md). That means a run the caller requested as read-only can auto-approve writes and shell commands instead of constraining them; wire Qwen read-only to --approval-mode plan and advertise the capability.

Useful? React with 👍 / 👎.

Comment thread src/main/agents/capabilities.ts Outdated
*/
omp: {
supportsResume: true,
supportsReadOnlyMode: false,

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restrict OMP tools when read-only is requested

OMP is now available through maestro-cli send, but if callers pass --read-only the generic spawner has no readOnlyArgs to add, so the run still gets OMP's full tool surface. OMP documents that its active tools can be pinned with --tools and lists read/search-only tools such as read, find, and search in its README (https://raw.githubusercontent.com/can1357/oh-my-pi/main/README.md), so the new agent should either wire a restricted --tools ... set and mark the capability true, or reject read-only instead of silently running with write and shell tools.

Useful? React with 👍 / 👎.

…ation)

- N1 (CodeRabbit Major): sanitize remote SSH stdout with stripAnsi before parsing omp models --json, matching the sibling line-split branch (shell-integration noise no longer empties the picker).
- N3 (Codex P2): qwen read-only used readOnlyArgs ['-y'] (YOLO auto-approve) which DEFEATS read-only. qwen-code v0.19.2 ships GA --approval-mode plan (denies write/shell/edit in non-interactive); switched to ['--approval-mode','plan'] + readOnlyCliEnforced true. buildAgentArgs skips batchModeArgs(-y) in read-only, so no -y/--approval-mode conflict.
- N4 (Codex P2): omp had no readOnlyArgs, so --read-only ran with full write/shell tools. Added readOnlyArgs ['--tools','read,grep,glob'] (search->grep, find->glob aliases) + readOnlyCliEnforced true + supportsReadOnlyMode true.
- N2 (Codex): INVALID, no change \u2014 qwen reads piped non-TTY stdin as the prompt automatically (input-format text default); Maestro only sets --output-format stream-json.
Verified against qwen-code v0.19.2 / omp v16.2.2 source. +regression tests (definitions, capabilities, agent-args).

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 3ad50cd20d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

workingDirArgs: (dir: string) => ['--include-directories', dir],
imageArgs: undefined,
modelArgs: (modelId: string) => ['-m', modelId],
promptArgs: (prompt: string) => ['-p', prompt],

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add Qwen's headless prompt flag on stdin spawns

Fresh evidence: the Windows raw-stdin path also skips promptArgs, so this is not limited to SSH. Qwen's headless docs list --prompt/-p as the flag that runs a prompt in headless mode and show stream JSON as qwen -p ... --output-format stream-json (https://qwenlm.github.io/qwen-code-docs/en/users/features/headless/); when Windows local or SSH spawns send the prompt through stdin, Maestro does not append this builder, so Qwen launches as qwen -y --output-format stream-json and can enter interactive mode or wait instead of emitting JSON. Add a stdin-safe headless flag for those paths, without duplicating the prompt text.

Useful? React with 👍 / 👎.

}
}

if (event.type === 'result' && this.isFailedResult(parsed)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Treat inline Qwen API errors as failures

Qwen's own CI wrapper treats final result text containing [API Error as failed even when is_error is false, because provider/model connection failures can be rendered inline in a nominally successful result (https://raw.githubusercontent.com/QwenLM/qwen-code/main/.github/workflows/qwen-code-pr-review.yml). This branch only reclassifies is_error === true, so those Qwen runs will be recorded as successful and can advance queues/Auto Run while the response is actually an API error; inspect the result text for Qwen's inline API error marker before returning a result.

Useful? React with 👍 / 👎.

hidden: true, // Not shipping. Kept for type/back-compat, hidden from UI.
binaryName: 'qwen3-coder',
command: 'qwen3-coder',
binaryName: 'qwen',

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Probe Qwen's official install locations

Once this visible agent resolves the qwen binary, detection depends on path-prober knowing where official installers place it. Qwen's docs say the recommended installer uses a standalone archive when available (https://qwenlm.github.io/qwen-code-docs/en/users/overview/), and the completed standalone-installer issue names ~/.qwen/bin/qwen with Windows ~/.qwen/bin/qwen.exe (QwenLM/qwen-code#3728); there is no qwen entry in getUnixKnownPaths or getWindowsKnownPaths, unlike OMP/Gemini, so packaged apps that cannot recover the user's shell PATH will mark Qwen unavailable after a supported install. Add those qwen paths to the direct probes.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant