allozaur/feat/chat slash commands (#26716)

* base : slash-command/misc foundation - model icon and focus-selector constants

* feat : slash-command picker and command parsing helpers

* refactor : wire command and @-mention pickers into the chat form

* ui : improve model selector keyboard navigation and load/dismiss

* feat: Unify markdown/raw-text rendering under one setting with migration

* fix: Misc fixes - tool-call subtitle, assistant wrap, progress guards

* feat: Clamp and style numeric settings inputs from registry bounds
This commit is contained in:
Aleksander Grygier
2026-08-07 20:20:01 +02:00
committed by GitHub
parent f8e30266d2
commit 6de1b63473
41 changed files with 1425 additions and 506 deletions
@@ -0,0 +1,44 @@
import { SET_WORKING_DIRECTORY_LABEL } from '$lib/constants/working-directory';
import { ChatFormCommandAction } from '$lib/enums';
import type { ChatFormCommand } from '$lib/types';
interface ChatCommandsOptions {
/** Gates `/model`. */
showModelSelector: boolean;
/** Gates `/prompt`. */
hasPrompts: () => boolean;
/** Gates `/cwd`. */
hasBuiltinTools: () => boolean;
}
/**
* The slash commands surfaced by the `/` command picker, in display order.
*
* Availability is supplied as predicates rather than store imports: this
* module is re-exported through the `$lib/constants` barrel, and importing
* stores at module load would create a circular dependency (the stores
* themselves import from `$lib/constants`).
*/
export function getChatCommands(options: ChatCommandsOptions): ChatFormCommand[] {
return [
{
name: 'prompt',
description: 'Insert an MCP prompt',
action: ChatFormCommandAction.PROMPT,
disabled: !options.hasPrompts()
},
{
name: 'cwd',
description: SET_WORKING_DIRECTORY_LABEL,
keywords: ['current working directory'],
action: ChatFormCommandAction.CWD,
disabled: !options.hasBuiltinTools()
},
{
name: 'model',
description: 'Select model',
action: ChatFormCommandAction.MODEL,
disabled: !options.showModelSelector
}
];
}
@@ -19,6 +19,9 @@ export const PANEL_CLASSES = `
export const CHAT_FORM_POPOVER_MAX_HEIGHT = 'max-h-80';
export const DIALOG_SUBMENU_CONTENT = 'w-60';
/** Selects the chat-form input to restore focus after model actions. */
export const CHAT_INPUT_FOCUS_SELECTOR = '[data-slot="input-area"] textarea';
/** Default Tailwind size class for inline icon components (lucide, etc.). */
export const ICON_CLASS_DEFAULT = 'h-4 w-4';
+1
View File
@@ -18,6 +18,7 @@ export * from './binary-detection';
export * from './built-in-tools';
export * from './cache';
export * from './chat-form';
export * from './chat-commands';
export * from './cli-flags';
export * from './code-blocks';
export * from './icons';
+1 -2
View File
@@ -23,7 +23,7 @@ export const SETTINGS_KEYS = {
SHOW_AGENTIC_TURN_STATS: 'showAgenticTurnStats',
SHOW_THOUGHT_IN_PROGRESS: 'showThoughtInProgress',
AUTO_MIC_ON_EMPTY: 'autoMicOnEmpty',
RENDER_USER_CONTENT_AS_MARKDOWN: 'renderUserContentAsMarkdown',
RENDER_CONTENT_AS_RAW_TEXT: 'renderContentAsRawText',
DISABLE_AUTO_SCROLL: 'disableAutoScroll',
ALWAYS_SHOW_SIDEBAR_ON_DESKTOP: 'alwaysShowSidebarOnDesktop',
FULL_HEIGHT_CODE_BLOCKS: 'fullHeightCodeBlocks',
@@ -33,7 +33,6 @@ export const SETTINGS_KEYS = {
SHOW_BUILD_VERSION: 'showBuildVersion',
SHOW_FULL_PATH_IN_MENTIONS: 'showFullPathInMentions',
SHOW_SYSTEM_MESSAGE: 'showSystemMessage',
RENDER_THINKING_AS_MARKDOWN: 'renderThinkingAsMarkdown',
MENTION_SEARCH_MAX_DEPTH: 'mentionSearchMaxDepth',
// Sampling
TEMPERATURE: 'temperature',
@@ -233,21 +233,13 @@ const SETTINGS_REGISTRY: Record<string, SettingsSectionEntry> = {
section: SETTINGS_SECTION_SLUGS.DISPLAY
},
{
key: SETTINGS_KEYS.RENDER_USER_CONTENT_AS_MARKDOWN,
label: 'Render user content as Markdown',
help: 'Render user messages using markdown formatting in the chat.',
key: SETTINGS_KEYS.RENDER_CONTENT_AS_RAW_TEXT,
label: 'Render content as raw text',
help: 'Display user, system and thinking content as plain text instead of formatted Markdown. Markdown is the default so that @-mention badges render in sent messages.',
defaultValue: false,
type: SettingsFieldType.CHECKBOX,
section: SETTINGS_SECTION_SLUGS.DISPLAY
},
{
key: SETTINGS_KEYS.RENDER_THINKING_AS_MARKDOWN,
label: 'Render thinking as Markdown',
help: 'Render the reasoning/thinking block content as formatted Markdown instead of plain text.',
defaultValue: true,
type: SettingsFieldType.CHECKBOX,
section: SETTINGS_SECTION_SLUGS.DISPLAY
},
{
key: SETTINGS_KEYS.FULL_HEIGHT_CODE_BLOCKS,
label: 'Use full height code blocks',
@@ -724,6 +716,9 @@ export const SETTINGS_CHAT_SECTIONS: SettingsSection[] = [
type: s.type,
isExperimental: s.isExperimental,
isPositiveInteger: s.isPositiveInteger,
placeholder: s.placeholder,
min: s.min,
max: s.max,
dependsOn: s.dependsOn,
help: s.help,
options: s.options,
+4 -1
View File
@@ -1,4 +1,4 @@
import { Search, Settings, SquarePen } from '@lucide/svelte';
import { Package, Search, Settings, SquarePen } from '@lucide/svelte';
import McpLogo from '$lib/components/app/mcp/McpLogo.svelte';
import type { Component } from 'svelte';
import { ROUTES } from './routes';
@@ -6,6 +6,9 @@ import { ROUTES } from './routes';
export const FORK_TREE_DEPTH_PADDING = 8;
export const SYSTEM_MESSAGE_PLACEHOLDER = 'System message';
/** Icon used for the model selector and the `/model` slash command. */
export const MODEL_SELECTOR_ICON = Package;
export const ICON_STRIP_TRANSITION_DURATION = 150;
export const ICON_STRIP_TRANSITION_DELAY_MULTIPLIER = 50;
@@ -8,6 +8,9 @@
export const GLOB_WILDCARD = '*';
/** Label shown for the working-directory picker / `/cwd` slash command. */
export const SET_WORKING_DIRECTORY_LABEL = 'Set working directory';
/** Character that starts and ends a glob character-class fragment. */
export const GLOB_RANGE_OPEN = '[';
export const GLOB_RANGE_CLOSE = ']';