mirror of
https://github.com/stablyai/orca.git
synced 2026-09-21 16:02:20 +00:00
fix(pi): use Pi configured provider for Source Control AI defaults (#21693)
* fix(pi): let Source Control AI use Pi configured default When Orca runs Pi for automatic branch names or commit messages without an explicit model override, omit --model so Pi resolves its configured provider. Preserve explicit discovered model selection and add regression coverage. * fix(pi): preserve discovered fallback for non-Pi agents Keep the configured-default sentinel behavior limited to agents whose default is the explicit CLI sentinel. Other dynamic agents still fall back to the first discovered model when their static default is unavailable. * test(pi): pin configured-default dry-run arguments Prove Source Control AI does not render the Pi configured-default sentinel as a literal model argument, and assert explicit model flag pairing positionally.
This commit is contained in:
@@ -57,7 +57,10 @@ export function finalizeModelDiscoveryOutput(
|
||||
}
|
||||
return { success: false, error: `${spec.label} returned no available models.` }
|
||||
}
|
||||
const defaultModelId = models.some((model) => model.id === spec.defaultModelId)
|
||||
// A sentinel model in the static spec (for example `default`) means the CLI
|
||||
// should keep its configured provider even when discovery lists concrete models.
|
||||
const defaultModelId =
|
||||
spec.defaultModelId === 'default' || models.some((model) => model.id === spec.defaultModelId)
|
||||
? spec.defaultModelId
|
||||
: models[0].id
|
||||
return staticModelDiscoveryResult(spec, models, defaultModelId, 'probe')
|
||||
|
||||
@@ -273,8 +273,32 @@ describe('discoverCommitMessageModelsLocal', () => {
|
||||
|
||||
await expect(pending).resolves.toMatchObject({
|
||||
success: true,
|
||||
defaultModelId: 'github-copilot/gpt-5.4-mini',
|
||||
models: [{ id: 'github-copilot/gpt-5.4-mini' }]
|
||||
defaultModelId: 'default',
|
||||
models: [{ id: 'default' }]
|
||||
})
|
||||
})
|
||||
|
||||
it('falls back to the first discovered non-Pi model when its static default is unavailable', async () => {
|
||||
const listeners = new Map<string, (value: unknown) => void>()
|
||||
const child = {
|
||||
pid: 123,
|
||||
kill: vi.fn(),
|
||||
stdout: { on: vi.fn((event, callback) => listeners.set(`stdout:${event}`, callback)) },
|
||||
stderr: { on: vi.fn((event, callback) => listeners.set(`stderr:${event}`, callback)) },
|
||||
stdin: { end: vi.fn() },
|
||||
on: vi.fn((event, callback) => listeners.set(event, callback))
|
||||
}
|
||||
spawnMock.mockReturnValue(child as never)
|
||||
|
||||
const pending = discoverCommitMessageModelsLocal('cursor', undefined)
|
||||
|
||||
listeners.get('stdout:data')?.(Buffer.from('gpt-5.2 - GPT-5.2\n'))
|
||||
listeners.get('close')?.(0)
|
||||
|
||||
await expect(pending).resolves.toMatchObject({
|
||||
success: true,
|
||||
defaultModelId: 'gpt-5.2',
|
||||
models: [{ id: 'gpt-5.2' }]
|
||||
})
|
||||
})
|
||||
|
||||
@@ -305,7 +329,7 @@ describe('discoverCommitMessageModelsLocal', () => {
|
||||
|
||||
await expect(pending).resolves.toMatchObject({
|
||||
success: true,
|
||||
defaultModelId: 'github-copilot/gpt-5.4-mini',
|
||||
defaultModelId: 'default',
|
||||
models: [{ id: 'github-copilot/gpt-5.4-mini' }, { id: 'openai-codex/gpt-5.5' }]
|
||||
})
|
||||
})
|
||||
|
||||
@@ -88,6 +88,20 @@ describe('planSourceControlCommitMessageGeneration', () => {
|
||||
expect(result.ok && result.commandLabel).toBe('echo issue {linkedIssue}')
|
||||
})
|
||||
|
||||
it('omits Pi configured-default sentinel from dry-run command labels', () => {
|
||||
const result = planSourceControlTextGeneration('commitMessage', {
|
||||
agentId: 'pi',
|
||||
model: 'default',
|
||||
commandInputTemplate: '{basePrompt}'
|
||||
})
|
||||
|
||||
expect(result.ok).toBe(true)
|
||||
if (result.ok) {
|
||||
expect(result.commandLabel).not.toContain('--model')
|
||||
expect(result.commandLabel).not.toContain('default')
|
||||
}
|
||||
})
|
||||
|
||||
it('shows per-action CLI arguments in dry-run command labels', () => {
|
||||
const result = planSourceControlTextGeneration('pullRequest', {
|
||||
agentId: 'codex',
|
||||
|
||||
@@ -46,7 +46,7 @@ describe('COMMIT_MESSAGE_AGENT_SPECS', () => {
|
||||
it('uses the strongest available defaults for core agents', () => {
|
||||
expect(COMMIT_MESSAGE_AGENT_SPECS.claude?.defaultModelId).toBe('sonnet')
|
||||
expect(COMMIT_MESSAGE_AGENT_SPECS.codex?.defaultModelId).toBe('gpt-5.5')
|
||||
expect(COMMIT_MESSAGE_AGENT_SPECS.pi?.defaultModelId).toBe('github-copilot/gpt-5.4-mini')
|
||||
expect(COMMIT_MESSAGE_AGENT_SPECS.pi?.defaultModelId).toBe('default')
|
||||
})
|
||||
|
||||
it('uses --prompt (not Claude --print) for Kimi non-interactive generation', () => {
|
||||
@@ -612,3 +612,24 @@ describe('buildArgs (Antigravity)', () => {
|
||||
expect(COMMIT_MESSAGE_AGENT_SPECS.antigravity?.defaultModelId).toBe('Gemini 3.5 Flash (Medium)')
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
describe('Pi Source Control AI model selection', () => {
|
||||
it('leaves provider selection to Pi for the config default', () => {
|
||||
const args = getCommitMessageAgentSpec('pi')!.buildArgs({
|
||||
prompt: 'Name a branch',
|
||||
model: 'default'
|
||||
})
|
||||
expect(args).not.toContain('--model')
|
||||
})
|
||||
|
||||
it('passes an explicit discovered Pi model through', () => {
|
||||
const args = getCommitMessageAgentSpec('pi')!.buildArgs({
|
||||
prompt: 'Name a branch',
|
||||
model: 'openai-codex/gpt-5.5'
|
||||
})
|
||||
const modelFlagIndex = args.indexOf('--model')
|
||||
expect(modelFlagIndex).toBeGreaterThanOrEqual(0)
|
||||
expect(args[modelFlagIndex + 1]).toBe('openai-codex/gpt-5.5')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -201,22 +201,20 @@ export function buildPrimaryCommitMessageAgentSpecs({
|
||||
'--no-context-files',
|
||||
'--mode',
|
||||
'text',
|
||||
'--model',
|
||||
model,
|
||||
...(model && model !== 'default' ? ['--model', model] : []),
|
||||
...(thinkingLevel ? ['--thinking', thinkingLevel] : [])
|
||||
],
|
||||
modelSource: 'dynamic',
|
||||
modelDiscovery: { binary: 'pi', args: ['--list-models'], parse: parsePiModels },
|
||||
models: [
|
||||
{
|
||||
// Why: Pi commonly authenticates through GitHub Copilot locally; using
|
||||
// that provider avoids selecting a raw OpenAI model when no key exists.
|
||||
id: 'github-copilot/gpt-5.4-mini',
|
||||
label: 'Github Copilot GPT 5.4 Mini',
|
||||
...withOpenAiThinking('gpt-5.4-mini')
|
||||
// Why: the unqualified choice lets Pi use its configured provider and
|
||||
// avoids forcing GitHub Copilot credentials during automation.
|
||||
id: 'default',
|
||||
label: 'Config default'
|
||||
}
|
||||
],
|
||||
defaultModelId: 'github-copilot/gpt-5.4-mini'
|
||||
defaultModelId: 'default'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user