Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ interface SlashItemMetadata extends Record<string, string> {
command: string
display: string
meta: string
rawText?: string
}

function textValue(value: unknown, fallback = ''): string {
Expand Down Expand Up @@ -91,7 +92,13 @@ export function useSlashCompletions(options: { gateway: HermesGateway | null }):
const metadata: SlashItemMetadata = {
command,
display,
meta
meta,
// Provide rawText so hermesDirectiveFormatter.serialize uses the
// direct-insertion path instead of the legacy @type:id fallback.
// Without this, the item.id (which includes a "|index" suffix for
// trigger-adapter uniqueness) leaks into the serialized chip text
// and the submitted command.
rawText: command
}

return {
Expand Down
15 changes: 14 additions & 1 deletion apps/desktop/src/app/chat/composer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { Button } from '@/components/ui/button'
import { useMediaQuery } from '@/hooks/use-media-query'
import { useResizeObserver } from '@/hooks/use-resize-observer'
import { chatMessageText } from '@/lib/chat-messages'
import { SLASH_COMMAND_RE } from '@/lib/chat-runtime'
import { DATA_IMAGE_URL_RE } from '@/lib/embedded-images'
import { triggerHaptic } from '@/lib/haptics'
import { cn } from '@/lib/utils'
Expand Down Expand Up @@ -1037,7 +1038,19 @@ export function ChatBar({
if (queueEdit) {
exitQueuedEdit('save')
} else if (busy) {
if (hasComposerPayload) {
// Slash commands should execute immediately even while the agent is
// busy — they're client-side operations (/yolo, /skin, /new, /help,
// etc.) or self-contained gateway RPCs (/status, /compress). onSubmit
// routes them to executeSlashCommand, which has its own per-command
// busy guard for commands that genuinely need an idle session (skill
// /send directives). Queuing them would make every slash command wait
// for the current turn to finish, which is how the TUI never behaves.
if (!attachments.length && SLASH_COMMAND_RE.test(draft.trim())) {
const submitted = draft
triggerHaptic('submit')
clearDraft()
void onSubmit(submitted)
} else if (hasComposerPayload) {
queueCurrentDraft()
} else {
// Stop button: an explicit interrupt must actually halt the running
Expand Down
Loading