Skip to content

fix(source-control): override the built-in model when a recipe sets --model#8740

Closed
xianjianlf2 wants to merge 1 commit into
stablyai:mainfrom
xianjianlf2:fix/recipe-model-flag-override-8722
Closed

fix(source-control): override the built-in model when a recipe sets --model#8740
xianjianlf2 wants to merge 1 commit into
stablyai:mainfrom
xianjianlf2:fix/recipe-model-flag-override-8722

Conversation

@xianjianlf2

Copy link
Copy Markdown
Contributor

What & why

Action Recipe "CLI arguments" were appended verbatim after Orca's generated agent command. Every agent spec's buildArgs already emits --model <model>, so a recipe that also sets --model produced a duplicate --model flag and Codex aborted:

error: the argument '--model <MODEL>' cannot be used multiple times

This made per-recipe model overrides impossible (#8722).

Fix

Treat --model/-m as a singleton in insertAdditionalAgentArgs (src/shared/commit-message-plan.ts): when a recipe supplies a model, it replaces Orca's generated model value in place (preserving argument position, so a trailing -c model_reasoning_effort=… stays intact) instead of adding a second flag. Repeatable flags like -c are left untouched and still append. When the base args contain no --model (e.g. custom-command agents), behavior is unchanged. This implements the issue author's recommended solution #1.

Tests

src/shared/commit-message-plan.test.ts:

  • Added regression tests for the --model override (Codex + stdin agents, and the -m alias) and a repeatable--c-flag non-override case (proves only singletons are deduplicated).
  • Updated the two pre-existing tests that had codified the buggy duplicate---model output.
  • vitest run … src/shared/commit-message-plan.test.ts16 passed. TDD red→green verified (the duplicate---model reproduction fails before the fix, passes after).

Cross-platform / SSH / git providers

Pure argv construction — no platform, path, SSH, or git-provider assumptions. Provider-neutral across all agent specs.

AI coding agent review summary

Change is localized to commit-message command assembly. Verified TDD red→green, confirmed repeatable flags (-c) still append while only --model/-m is deduplicated, and that agents without a base --model are unaffected.

X: @mark86202384100

Closes #8722

…-model

Action recipe CLI arguments were appended verbatim after Orca's generated
Codex command, so a recipe `--model` produced a duplicate `--model` flag and
Codex aborted with "the argument '--model <MODEL>' cannot be used multiple
times". Treat `--model`/`-m` as a singleton: a recipe-supplied model now
replaces Orca's generated model in place instead of adding a second flag.

Closes stablyai#8722
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Updated command-plan argument merging so recipe-provided --model or -m values replace generated model arguments without duplication. Other arguments continue to be appended or inserted through existing paths. Tests cover stdin-agent sandbox arguments, Codex reasoning-effort settings, OpenCode model overrides, and repeatable configuration flags.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and concisely describes the main change: overriding the built-in model when a recipe sets --model.
Description check ✅ Passed The description covers the change, tests, cross-platform review, and notes, with only minor template gaps like screenshots and a dedicated security audit.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: ca163263-b5ce-43ff-97a2-bd5fe7aa3432

📥 Commits

Reviewing files that changed from the base of the PR and between e0edc8e and 5ee0020.

📒 Files selected for processing (2)
  • src/shared/commit-message-plan.test.ts
  • src/shared/commit-message-plan.ts

Comment on lines +71 to +113
// Why: `--model`/`-m` is a singleton flag — Codex rejects a repeated one with
// "cannot be used multiple times". When a recipe's CLI arguments set the model,
// it must override Orca's generated model in place instead of appending a second
// occurrence.
const MODEL_FLAGS = new Set(['--model', '-m'])

function readModelOverride(
agentArgs: string[]
): { value: string; index: number; consumed: number } | null {
for (let i = 0; i < agentArgs.length; i++) {
const token = agentArgs[i]
const equalsMatch = /^(?:--model|-m)=(.*)$/s.exec(token)
if (equalsMatch) {
return { value: equalsMatch[1], index: i, consumed: 1 }
}
if (MODEL_FLAGS.has(token) && i + 1 < agentArgs.length && !agentArgs[i + 1].startsWith('-')) {
return { value: agentArgs[i + 1], index: i, consumed: 2 }
}
}
return null
}

function applyModelFlagOverride(
baseArgs: string[],
agentArgs: string[]
): { baseArgs: string[]; agentArgs: string[] } {
const override = readModelOverride(agentArgs)
if (!override) {
return { baseArgs, agentArgs }
}
const baseIndex = baseArgs.findIndex(
(token, i) =>
MODEL_FLAGS.has(token) && i + 1 < baseArgs.length && !baseArgs[i + 1].startsWith('-')
)
if (baseIndex === -1) {
return { baseArgs, agentArgs }
}
const nextBase = [...baseArgs]
nextBase[baseIndex + 1] = override.value
const nextAgent = [...agentArgs]
nextAgent.splice(override.index, override.consumed)
return { baseArgs: nextBase, agentArgs: nextAgent }
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Only the first --model/-m occurrence in agentArgs is consumed.

readModelOverride returns on the first match; if a recipe's agentArgs string happens to contain the model flag twice (e.g., assembled from two argument fragments), the second occurrence is never spliced out and gets appended verbatim by the final merge step in insertAdditionalAgentArgs. That reproduces the exact duplicate---model failure this PR is fixing, just for a slightly different input shape.

🐛 Proposed fix: consume every model-flag occurrence, keeping the last as the effective override
 function applyModelFlagOverride(
   baseArgs: string[],
   agentArgs: string[]
 ): { baseArgs: string[]; agentArgs: string[] } {
-  const override = readModelOverride(agentArgs)
+  let remainingAgentArgs = agentArgs
+  let override: { value: string; index: number; consumed: number } | null = null
+  let found = readModelOverride(remainingAgentArgs)
+  while (found) {
+    override = found
+    remainingAgentArgs = [
+      ...remainingAgentArgs.slice(0, found.index),
+      ...remainingAgentArgs.slice(found.index + found.consumed)
+    ]
+    found = readModelOverride(remainingAgentArgs)
+  }
   if (!override) {
-    return { baseArgs, agentArgs }
+    return { baseArgs, agentArgs: remainingAgentArgs }
   }
   const baseIndex = baseArgs.findIndex(
     (token, i) =>
       MODEL_FLAGS.has(token) && i + 1 < baseArgs.length && !baseArgs[i + 1].startsWith('-')
   )
   if (baseIndex === -1) {
-    return { baseArgs, agentArgs }
+    return { baseArgs, agentArgs: remainingAgentArgs }
   }
   const nextBase = [...baseArgs]
   nextBase[baseIndex + 1] = override.value
-  const nextAgent = [...agentArgs]
-  nextAgent.splice(override.index, override.consumed)
-  return { baseArgs: nextBase, agentArgs: nextAgent }
+  return { baseArgs: nextBase, agentArgs: remainingAgentArgs }
 }
🧰 Tools
🪛 OpenGrep (1.25.0)

[ERROR] 82-82: Dynamic command passed to child_process.exec/execSync. Use child_process.execFile or spawn with an argument array instead.

(coderabbit.command-injection.exec-js)

@nwparker

nwparker commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Thank you for jumping on #8722, @xianjianlf2. I compared this after first opening independent PR #8773. I selected #8773 as the integration path because it is on current main, keeps the -m alias scoped to Codex, and covers equals/attached-short forms, the -- terminator, sibling args, and no-override behavior. Your in-place replacement idea was the strongest part of this implementation and is explicitly incorporated and credited in #8773 so the reasoning-effort ordering remains stable. Closing this one in favor of the combined PR.

@nwparker nwparker closed this Jul 14, 2026
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.

[Bug]: Recipe CLI arguments cannot override Codex model because Orca adds --model twice

2 participants