Files
orca/tests/e2e/omp-model-picker.spec.ts
NeilandSudoAI-DEV ae9c06c941 feat(omp): discover and switch native-chat models on desktop and mobile (#20612)
* fix(omp): discover and switch native-chat models

Report the running OMP provider/model and discover available choices on
the execution host for desktop and mobile. Register an extension command
to switch through the OMP API because its TUI does not accept /model args.
Advertise that command in status so older hosts remain read-only.

Addresses the OMP portion of #17603; Pi chat enablement remains separate.
Model reporting begins on lifecycle activity; no startup status is invented.

Co-authored-by: SudoAI-DEV <220139811+SudoAI-DEV@users.noreply.github.com>

* refactor(omp): check generated model metadata types

* test(omp): verify model picker command and reported selection

* test(omp): add repeatable real model-switch runtime proof

* test(omp): require model capability delivery in runtime smoke

* fix(mobile): decode OMP model discovery through RPC operations

* fix(omp): preserve exact reported model selectors

* fix(omp): preserve generated extension syntax after rebase

* fix(omp): merge generated harness UI context types

* test(omp): model switching keeps one session manager

* test(omp): include transcript path in model status proof

* test(omp): avoid renderer error-type union

* test(omp): keep renderer test type explicit

---------

Co-authored-by: SudoAI-DEV <220139811+SudoAI-DEV@users.noreply.github.com>
2026-09-19 05:11:48 -07:00

112 lines
3.8 KiB
TypeScript

import { readFile, writeFile } from 'node:fs/promises'
import { buildShellCommandFromArgv } from '../../src/shared/tui-agent-startup-shell'
import { test, expect } from './helpers/orca-app'
import { ensureTerminalVisible, waitForActiveWorktree, waitForSessionReady } from './helpers/store'
import {
execInTerminal,
waitForActivePaneHookDescriptor,
waitForActivePanePtyId,
waitForActiveTerminalManager
} from './helpers/terminal'
test('OMP model picker dispatches its advertised command and adopts the host report', async ({
orcaPage,
electronApp
}, testInfo) => {
test.skip(process.platform === 'win32', 'POSIX PTY capture fixture')
await waitForSessionReady(orcaPage)
await waitForActiveWorktree(orcaPage)
await ensureTerminalVisible(orcaPage)
await waitForActiveTerminalManager(orcaPage)
const descriptor = await waitForActivePaneHookDescriptor(orcaPage)
const ptyId = await waitForActivePanePtyId(orcaPage)
const output = testInfo.outputPath('model-command.txt')
const script = testInfo.outputPath('capture.cjs')
await writeFile(
script,
`const fs = require('node:fs'); let data = ''; process.stdin.setRawMode(true); process.stdin.on('data', chunk => { data += chunk; fs.writeFileSync(${JSON.stringify(output)}, data); });`
)
await execInTerminal(
orcaPage,
ptyId,
buildShellCommandFromArgv([process.execPath, script], 'posix')
)
await electronApp.evaluate(({ ipcMain }) => {
ipcMain.removeHandler('git:discoverCommitMessageModels')
ipcMain.handle('git:discoverCommitMessageModels', () => ({
success: true,
catalogOrigin: 'probe',
models: [
{ id: 'anthropic/claude-sonnet-4-5', label: 'Sonnet 4.5' },
{ id: 'anthropic/claude-sonnet-4-6', label: 'Sonnet 4.6' }
]
}))
})
await orcaPage.evaluate(async ({ paneKey, worktreeId }) => {
const settings = await window.api.settings.set({ experimentalNativeChat: true })
const store = window.__store
if (!store) {
throw new Error('Store unavailable')
}
store.setState({ settings })
const state = store.getState()
state.setAgentStatus(
paneKey,
{
state: 'idle',
prompt: '',
agentType: 'omp',
model: 'anthropic/claude-sonnet-4-5',
modelSwitchCommand: 'orca-model'
},
'OMP',
undefined,
{ worktreeId }
)
const [tabId] = paneKey.split(':')
const tab = (state.unifiedTabsByWorktree[worktreeId] ?? []).find(
(tab) => tab.contentType === 'terminal' && tab.entityId === tabId
)
if (!tab) {
throw new Error('Terminal tab unavailable')
}
state.toggleTabViewMode(tab.id)
}, descriptor)
const picker = orcaPage.getByRole('button', { name: 'Model Sonnet 4.5', exact: true })
await expect(picker).toBeVisible()
await picker.click()
await expect(
orcaPage.getByRole('menuitemradio', { name: 'Sonnet 4.6', exact: true })
).toBeVisible()
await orcaPage.screenshot({
animations: 'disabled',
path: testInfo.outputPath('omp-model-choices.png')
})
await orcaPage.getByRole('menuitemradio', { name: 'Sonnet 4.6', exact: true }).click()
await expect
.poll(async () => readFile(output, 'utf8').catch(() => ''))
.toContain('/orca-model anthropic/claude-sonnet-4-6')
await orcaPage.evaluate(({ paneKey, worktreeId }) => {
window.__store?.getState().setAgentStatus(
paneKey,
{
state: 'idle',
prompt: '',
agentType: 'omp',
model: 'anthropic/claude-sonnet-4-6',
modelSwitchCommand: 'orca-model'
},
'OMP',
undefined,
{ worktreeId }
)
}, descriptor)
await expect(
orcaPage.getByRole('button', { name: 'Model Sonnet 4.6', exact: true })
).toBeVisible()
await orcaPage.screenshot({
animations: 'disabled',
path: testInfo.outputPath('omp-model-reported.png')
})
})