mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
fix(recipes): let Codex model args override defaults (#8773)
* fix(recipes): let Codex model args override defaults * fix(recipes): harden Codex model override forms
This commit is contained in:
@@ -215,12 +215,51 @@ describe('planCommitMessageGeneration', () => {
|
||||
})
|
||||
})
|
||||
|
||||
it('appends per-action CLI arguments after the built-in model args for stdin agents', () => {
|
||||
it.each([
|
||||
['long option', '--model gpt-5.6-luna', ['--model', 'gpt-5.6-luna'], []],
|
||||
['short option', '-m gpt-5.6-luna', ['-m', 'gpt-5.6-luna'], []],
|
||||
['equals form', '--model=gpt-5.6-luna', ['--model=gpt-5.6-luna'], []],
|
||||
['attached short form', '-mgpt-5.6-luna', ['-mgpt-5.6-luna'], []],
|
||||
[
|
||||
'sibling arguments',
|
||||
'--model gpt-5.6-luna --sandbox read-only',
|
||||
['--model', 'gpt-5.6-luna'],
|
||||
['--sandbox', 'read-only']
|
||||
]
|
||||
])(
|
||||
'lets Codex recipe args override the generated model via %s',
|
||||
(_, agentArgs, overrideArgs, trailingArgs) => {
|
||||
const result = planCommitMessageGeneration(
|
||||
{ agentId: 'codex', model: 'gpt-5.4-mini', thinkingLevel: 'medium', agentArgs },
|
||||
'PROMPT'
|
||||
)
|
||||
|
||||
expect(result).toMatchObject({
|
||||
ok: true,
|
||||
plan: {
|
||||
args: [
|
||||
'exec',
|
||||
'--ephemeral',
|
||||
'--skip-git-repo-check',
|
||||
'-s',
|
||||
'read-only',
|
||||
...overrideArgs,
|
||||
'-c',
|
||||
'model_reasoning_effort=medium',
|
||||
...trailingArgs
|
||||
],
|
||||
stdinPayload: 'PROMPT'
|
||||
}
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
it('keeps Codex recipe arguments unchanged when they do not override the model', () => {
|
||||
const result = planCommitMessageGeneration(
|
||||
{
|
||||
agentId: 'codex',
|
||||
model: 'gpt-5.4-mini',
|
||||
agentArgs: '--model gpt-5.5 --sandbox read-only'
|
||||
agentArgs: '--sandbox workspace-write'
|
||||
},
|
||||
'PROMPT'
|
||||
)
|
||||
@@ -236,12 +275,38 @@ describe('planCommitMessageGeneration', () => {
|
||||
'read-only',
|
||||
'--model',
|
||||
'gpt-5.4-mini',
|
||||
'--model',
|
||||
'gpt-5.5',
|
||||
'--sandbox',
|
||||
'read-only'
|
||||
],
|
||||
stdinPayload: 'PROMPT'
|
||||
'workspace-write'
|
||||
]
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
it('keeps the generated Codex model when model-like text follows an option terminator', () => {
|
||||
const result = planCommitMessageGeneration(
|
||||
{
|
||||
agentId: 'codex',
|
||||
model: 'gpt-5.4-mini',
|
||||
agentArgs: '-- --model literal'
|
||||
},
|
||||
'PROMPT'
|
||||
)
|
||||
|
||||
expect(result).toMatchObject({
|
||||
ok: true,
|
||||
plan: {
|
||||
args: [
|
||||
'exec',
|
||||
'--ephemeral',
|
||||
'--skip-git-repo-check',
|
||||
'-s',
|
||||
'read-only',
|
||||
'--model',
|
||||
'gpt-5.4-mini',
|
||||
'--',
|
||||
'--model',
|
||||
'literal'
|
||||
]
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
@@ -68,6 +68,69 @@ function planAdditionalAgentArgs(
|
||||
return { ok: true, args: tokenized.tokens }
|
||||
}
|
||||
|
||||
const CODEX_MODEL_OPTION_ALIASES = ['--model', '-m'] as const
|
||||
|
||||
function matchesOption(token: string, aliases: readonly string[]): boolean {
|
||||
return aliases.some(
|
||||
(alias) =>
|
||||
token === alias ||
|
||||
token.startsWith(`${alias}=`) ||
|
||||
(alias.startsWith('-') &&
|
||||
!alias.startsWith('--') &&
|
||||
token.startsWith(alias) &&
|
||||
token.length > alias.length)
|
||||
)
|
||||
}
|
||||
|
||||
function findOptionOccurrence(
|
||||
tokens: string[],
|
||||
aliases: readonly string[],
|
||||
stopAtTerminator: boolean
|
||||
): { index: number; consumed: number } | null {
|
||||
for (let index = 0; index < tokens.length; index += 1) {
|
||||
const token = tokens[index]
|
||||
if (stopAtTerminator && token === '--') {
|
||||
break
|
||||
}
|
||||
if (!matchesOption(token, aliases)) {
|
||||
continue
|
||||
}
|
||||
const nextToken = tokens[index + 1]
|
||||
const consumesNext =
|
||||
aliases.includes(token) && nextToken !== undefined && !nextToken.startsWith('-')
|
||||
return { index, consumed: consumesNext ? 2 : 1 }
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function applyRecipeOptionOverride(args: {
|
||||
generatedArgs: string[]
|
||||
recipeArgs: string[]
|
||||
aliases: readonly string[]
|
||||
}): { generatedArgs: string[]; recipeArgs: string[] } {
|
||||
const recipeOption = findOptionOccurrence(args.recipeArgs, args.aliases, true)
|
||||
const generatedOption = findOptionOccurrence(args.generatedArgs, args.aliases, false)
|
||||
if (!recipeOption || !generatedOption) {
|
||||
return { generatedArgs: args.generatedArgs, recipeArgs: args.recipeArgs }
|
||||
}
|
||||
|
||||
const overrideTokens = args.recipeArgs.slice(
|
||||
recipeOption.index,
|
||||
recipeOption.index + recipeOption.consumed
|
||||
)
|
||||
return {
|
||||
generatedArgs: [
|
||||
...args.generatedArgs.slice(0, generatedOption.index),
|
||||
...overrideTokens,
|
||||
...args.generatedArgs.slice(generatedOption.index + generatedOption.consumed)
|
||||
],
|
||||
recipeArgs: [
|
||||
...args.recipeArgs.slice(0, recipeOption.index),
|
||||
...args.recipeArgs.slice(recipeOption.index + recipeOption.consumed)
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
function insertAdditionalAgentArgs(args: {
|
||||
baseArgs: string[]
|
||||
agentArgs: string[]
|
||||
@@ -164,9 +227,19 @@ export function planCommitMessageGeneration(
|
||||
if (!agentArgs.ok) {
|
||||
return agentArgs
|
||||
}
|
||||
// Why: Codex rejects repeated singleton model flags. Recipe CLI arguments
|
||||
// are the more specific setting, so they replace Orca's generated model.
|
||||
const overriddenArgs =
|
||||
input.agentId === 'codex'
|
||||
? applyRecipeOptionOverride({
|
||||
generatedArgs: baseArgs,
|
||||
recipeArgs: agentArgs.args,
|
||||
aliases: CODEX_MODEL_OPTION_ALIASES
|
||||
})
|
||||
: { generatedArgs: baseArgs, recipeArgs: agentArgs.args }
|
||||
const args = insertAdditionalAgentArgs({
|
||||
baseArgs,
|
||||
agentArgs: agentArgs.args,
|
||||
baseArgs: overriddenArgs.generatedArgs,
|
||||
agentArgs: overriddenArgs.recipeArgs,
|
||||
promptDelivery: spec.promptDelivery,
|
||||
prompt: argvPrompt
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user