Files
orca/src/shared/native-chat-agent-profiles.test.ts
T
Brennan BensonandMerge Sim ecd7b19ad4 fix(native-chat): pass agent-implemented slash commands through to the agent (#19929)
* fix(native-chat): pass agent-implemented slash commands through to the agent

Claim what the host implements; pass through what the agent implements.
Claude's harness expands a slash command out of the message text, so the
host claimed catalog commands it had no way to run and answered "/init is
not available in chat sessions" for commands Claude does run. Codex's
app-server has no slash parser at all, so its catalog stays claimed —
except /goal, which the model carries out through its own goal tools.

* fix(native-chat): offer the agent-run commands in the structured picker

Codex reports no command catalog, so its structured `/` menu is the host
fallback -- which listed only the host's own commands and hid `/goal`, the
one command the model itself acts on. The picker now appends the profile's
text-driven commands, described from the curated catalog, so a command that
passes through is discoverable and not merely typable.

The menu invariant holds either way: a pick is answered by the host or run
by the agent, never refused with "not available in chat sessions".

* fix mobile structured command reconciliation

* fix(mobile): keep native chat controller within lint budget

* fix mobile controller lint budget

---------

Co-authored-by: Merge Sim <sim@local>
2026-09-10 20:50:40 -07:00

59 lines
2.1 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import {
getHostClaimedNativeChatCommands,
getNativeChatAgentProfile,
getVerifiedNativeChatCommands
} from './native-chat-agent-profiles'
describe('native chat agent picker profiles', () => {
// The composer types the same `/` for every agent; skillPrefix is only the
// form a picked skill is written as.
it('keeps Codex skills invocable as dollar tokens', () => {
expect(getNativeChatAgentProfile('codex')).toMatchObject({
skillPrefix: '$',
skillSourceOwner: 'codex'
})
})
it('writes Claude-family and Grok skills as slash tokens', () => {
expect(getNativeChatAgentProfile('claude')).toMatchObject({
skillPrefix: '/',
skillSourceOwner: 'claude'
})
expect(getNativeChatAgentProfile('openclaude')).toMatchObject({ skillSourceOwner: 'claude' })
expect(getNativeChatAgentProfile('grok')).toMatchObject({
skillPrefix: '/',
skillSourceOwner: 'grok'
})
})
it('does not grant custom or unverified agents a skill grammar', () => {
expect(getNativeChatAgentProfile('custom-agent')).toBeNull()
})
})
describe('host-claimed native chat commands', () => {
function names(agent: string): string[] {
return getHostClaimedNativeChatCommands(agent).map((command) => command.name)
}
// Claude's harness expands a slash command out of the message body, so claiming
// its catalog only answered "/init is not available" for commands that do run.
it('claims nothing from the Claude-family catalog', () => {
expect(names('claude')).toEqual([])
expect(names('openclaude')).toEqual([])
})
it('keeps the Codex catalog claimed except the model-driven /goal', () => {
expect(names('codex')).toContain('permissions')
expect(names('codex')).toContain('vim')
expect(names('codex')).not.toContain('goal')
expect(getVerifiedNativeChatCommands('codex').map((command) => command.name)).toContain('goal')
})
it('claims the whole catalog for agents with no pass-through policy', () => {
expect(names('custom-agent')).toEqual(['clear', 'help'])
expect(names('grok')).toEqual([])
})
})