feat(codex): support slash controls and skill discovery (#545)

* feat(codex): resolve slash controls before sending to Codex

* feat(codex): discover commands and skills

* fix(codex): handle slash commands before attachments

* fix(codex): block remaining unsupported built-ins
This commit is contained in:
CoColate
2026-04-29 09:20:11 +08:00
committed by GitHub
parent 9c117679f0
commit 9d2dec137b
12 changed files with 571 additions and 81 deletions
@@ -199,20 +199,12 @@ export function HappyComposer(props: {
markSkillUsed(suggestion.text.slice(1))
}
// For Codex user prompts with content, expand the content instead of command name
let textToInsert = suggestion.text
let addSpace = true
if (agentFlavor === 'codex' && suggestion.source !== 'builtin' && suggestion.content) {
textToInsert = suggestion.content
addSpace = false
}
const result = applySuggestion(
inputState.text,
inputState.selection,
textToInsert,
suggestion.text,
autocompletePrefixes,
addSpace
true
)
api.composer().setText(result.text)
@@ -233,7 +225,7 @@ export function HappyComposer(props: {
}, 0)
haptic('light')
}, [api, suggestions, inputState, autocompletePrefixes, haptic, agentFlavor])
}, [api, suggestions, inputState, autocompletePrefixes, haptic])
const abortDisabled = controlsDisabled || isAborting || !threadIsRunning
const switchDisabled = controlsDisabled || isSwitching || !controlledByUser
+1 -21
View File
@@ -20,8 +20,6 @@ import { HappyComposer } from '@/components/AssistantChat/HappyComposer'
import { HappyThread } from '@/components/AssistantChat/HappyThread'
import { useHappyRuntime } from '@/lib/assistant-runtime'
import { createAttachmentAdapter } from '@/lib/attachmentAdapter'
import { findUnsupportedCodexBuiltinSlashCommand } from '@/lib/codexSlashCommands'
import { useToast } from '@/lib/toast-context'
import { useTranslation } from '@/lib/use-translation'
import { SessionHeader } from '@/components/SessionHeader'
import { TeamPanel } from '@/components/TeamPanel'
@@ -67,7 +65,6 @@ export function SessionChat(props: {
availableSlashCommands?: readonly SlashCommand[]
}) {
const { haptic } = usePlatform()
const { addToast } = useToast()
const { t } = useTranslation()
const navigate = useNavigate()
const sessionInactive = !props.session.active
@@ -349,26 +346,9 @@ export function SessionChat(props: {
}, [navigate, props.session.id])
const handleSend = useCallback((text: string, attachments?: AttachmentMetadata[]) => {
if (agentFlavor === 'codex') {
const unsupportedCommand = findUnsupportedCodexBuiltinSlashCommand(
text,
props.availableSlashCommands ?? []
)
if (unsupportedCommand) {
haptic.notification('error')
addToast({
title: t('composer.codexSlashUnsupported.title'),
body: t('composer.codexSlashUnsupported.body', { command: `/${unsupportedCommand}` }),
sessionId: props.session.id,
url: `/sessions/${props.session.id}`
})
return
}
}
props.onSend(text, attachments)
setForceScrollToken((token) => token + 1)
}, [agentFlavor, props.availableSlashCommands, props.onSend, props.session.id, addToast, haptic, t])
}, [props.onSend])
const attachmentAdapter = useMemo(() => {
if (!props.session.active) {