mirror of
https://github.com/stablyai/orca.git
synced 2026-11-14 18:07:45 +00:00
fix(agent-picker): list agents named by the search before other agents' model setups (#39806)
* fix(agent-picker): list agents named by the search before other agents' model setups Typing "codex" in the agent picker showed OpenCode/Cursor model setups (e.g. "OpenCode · GPT-5 Codex") above the Codex agent itself, and Enter picked the first setup. Direct agent matches now render first and are the Enter target. * test(agent-picker): assert search highlight and Enter target for named agent * test(agent-picker): import fireEvent after rebase
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
// @vitest-environment happy-dom
|
||||
import { cleanup, render, screen } from '@testing-library/react'
|
||||
import { cleanup, fireEvent, render, screen } from '@testing-library/react'
|
||||
import { afterEach, expect, it, vi } from 'vitest'
|
||||
import { useState, type ComponentProps } from 'react'
|
||||
import userEvent from '@testing-library/user-event'
|
||||
@@ -93,3 +93,48 @@ it('includes blank terminal in keyboard results and filters it for agent and mod
|
||||
await user.type(screen.getByRole('textbox'), 'astra{Enter}')
|
||||
expect(screen.getByLabelText('Selection').textContent).toBe('codex:astra')
|
||||
})
|
||||
|
||||
it('lists an agent named by the query before other agents’ model setups', () => {
|
||||
const codex: AgentPickerEntry = {
|
||||
agent: 'codex',
|
||||
label: 'Codex',
|
||||
rows: [{ agent: 'codex', kind: 'cli' }],
|
||||
surfaces: ['terminal'],
|
||||
defaultSurface: 'terminal',
|
||||
terminal: {},
|
||||
structured: {},
|
||||
catalog: { origin: 'probe', fetchedAt: 1, models: [] }
|
||||
}
|
||||
const opencode: AgentPickerEntry = {
|
||||
...codex,
|
||||
agent: 'opencode',
|
||||
label: 'OpenCode',
|
||||
rows: [{ agent: 'opencode', kind: 'cli' }],
|
||||
catalog: {
|
||||
origin: 'probe',
|
||||
fetchedAt: 1,
|
||||
models: [{ id: 'gpt-5-codex', label: 'GPT-5 Codex', isDefault: false, efforts: [] }]
|
||||
}
|
||||
}
|
||||
const launch = vi.fn()
|
||||
render(
|
||||
<DropdownMenu defaultOpen modal={false}>
|
||||
<DropdownMenuTrigger>Open</DropdownMenuTrigger>
|
||||
<DropdownMenuContent>
|
||||
<AgentLaunchPickerMenu entries={[opencode, codex]} runLaunch={launch} />
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)
|
||||
fireEvent.focus(screen.getByRole('textbox'))
|
||||
fireEvent.change(screen.getByRole('textbox'), { target: { value: 'codex' } })
|
||||
const items = screen.getAllByRole('menuitem').map((item) => item.textContent)
|
||||
expect(items[0]).toContain('Codex')
|
||||
expect(items[0]).not.toContain('OpenCode')
|
||||
expect(items.some((text) => text?.includes('OpenCode · GPT-5 Codex'))).toBe(true)
|
||||
const highlighted = document.querySelectorAll('[data-search-default]')
|
||||
expect(highlighted).toHaveLength(1)
|
||||
expect(highlighted[0].textContent).toContain('Codex')
|
||||
expect(highlighted[0].textContent).not.toContain('OpenCode')
|
||||
fireEvent.keyDown(screen.getByRole('textbox'), { key: 'Enter' })
|
||||
expect(launch).toHaveBeenCalledWith({ agent: 'codex', kind: 'cli' }, undefined)
|
||||
})
|
||||
|
||||
@@ -144,8 +144,10 @@ export function AgentLaunchPickerMenu({
|
||||
// Why: Enter in the search picks the first enabled row, so show it highlighted like cmdk comboboxes.
|
||||
const enabled = (entry: AgentPickerEntry) => !disabled && entry.surfaces.length > 0
|
||||
const showBlankTerminal = !!onSelectBlankTerminal && agentPickerBlankTerminalMatches(query)
|
||||
const firstSetup = showBlankTerminal ? undefined : setups.find((setup) => enabled(setup.entry))
|
||||
const firstEntry = showBlankTerminal || firstSetup ? undefined : visible.find(enabled)
|
||||
// Why: a query naming an agent ("codex") should surface that agent before other agents' model setups.
|
||||
const firstEntry = showBlankTerminal ? undefined : visible.find(enabled)
|
||||
const firstSetup =
|
||||
showBlankTerminal || firstEntry ? undefined : setups.find((setup) => enabled(setup.entry))
|
||||
const showSearchDefault = searchFocused && query.trim().length > 0
|
||||
return (
|
||||
<div ref={root} data-agent-launch-picker="true">
|
||||
@@ -212,6 +214,30 @@ export function AgentLaunchPickerMenu({
|
||||
</DropdownMenuItem>
|
||||
</AgentDefaultContextMenu>
|
||||
) : null}
|
||||
{visible.map((entry) => {
|
||||
const source = draftForEntry?.(entry)
|
||||
return (
|
||||
<AgentPickerMenuRow
|
||||
key={entry.agent}
|
||||
draftScope={draftScope}
|
||||
entry={entry}
|
||||
mode={mode}
|
||||
searchDefault={showSearchDefault && entry === firstEntry}
|
||||
source={source}
|
||||
selected={value?.agent === entry.agent ? value : undefined}
|
||||
setupDisabled={setupDisabled}
|
||||
openSetup={openSetup}
|
||||
onSetupOpenChange={setActiveSetup}
|
||||
disabled={disabled}
|
||||
terminalBlocked={terminalBlocked}
|
||||
runLaunch={runLaunch}
|
||||
onSelectAgent={onSelectAgent}
|
||||
isDefault={defaultAgent === entry.agent}
|
||||
onSetDefault={onSetDefault}
|
||||
shortcut={mode !== 'select' ? shortcutLabels?.get(entry.agent) : undefined}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
{setups.map((setup) => {
|
||||
const source = draftForEntry?.(setup.entry)
|
||||
return (
|
||||
@@ -237,30 +263,6 @@ export function AgentLaunchPickerMenu({
|
||||
/>
|
||||
)
|
||||
})}
|
||||
{visible.map((entry) => {
|
||||
const source = draftForEntry?.(entry)
|
||||
return (
|
||||
<AgentPickerMenuRow
|
||||
key={entry.agent}
|
||||
draftScope={draftScope}
|
||||
entry={entry}
|
||||
mode={mode}
|
||||
searchDefault={showSearchDefault && entry === firstEntry}
|
||||
source={source}
|
||||
selected={value?.agent === entry.agent ? value : undefined}
|
||||
setupDisabled={setupDisabled}
|
||||
openSetup={openSetup}
|
||||
onSetupOpenChange={setActiveSetup}
|
||||
disabled={disabled}
|
||||
terminalBlocked={terminalBlocked}
|
||||
runLaunch={runLaunch}
|
||||
onSelectAgent={onSelectAgent}
|
||||
isDefault={defaultAgent === entry.agent}
|
||||
onSetDefault={onSetDefault}
|
||||
shortcut={mode !== 'select' ? shortcutLabels?.get(entry.agent) : undefined}
|
||||
/>
|
||||
)
|
||||
})}
|
||||
{!showBlankTerminal && !visible.length && !setups.length ? (
|
||||
<DropdownMenuItem disabled>
|
||||
{t('auto.components.agent.AgentCombobox.579c768bde', 'No agents match your search.')}
|
||||
|
||||
Reference in New Issue
Block a user