fix: title web slash command sessions (#1599)

* fix web slash command session titles

* docs update slash command title pr fragment

---------

Co-authored-by: Codex <codex@openai.com>
This commit is contained in:
ekko
2026-06-16 18:42:43 +08:00
committed by GitHub
parent c23760aba5
commit 0cb047c31e
3 changed files with 45 additions and 3 deletions
@@ -0,0 +1,6 @@
---
date: 2026-06-16
pr: 1599
feature: Web slash command session titles
impact: New Web UI slash-command sessions now use the command text for their initial title instead of the generic Bridge command title.
---
@@ -88,7 +88,7 @@ export async function handleSessionCommand(
): Promise<void> {
const state = getOrCreateSession(ctx.sessionMap, sessionId)
ctx.socket.join(`session:${sessionId}`)
ensureCommandSession(sessionId, ctx)
ensureCommandSession(sessionId, command, ctx)
const isKnownCommand = Boolean(COMMAND_ALIASES[command.rawName])
if (command.name !== 'plan' && command.name !== 'skill' && isKnownCommand) {
persistCommandMessage(sessionId, state, `/${command.rawName}${command.args ? ` ${command.args}` : ''}`)
@@ -827,17 +827,23 @@ function formatReloadSkillItem(item: unknown): string {
return description ? `${name}: ${description}` : name
}
function ensureCommandSession(sessionId: string, ctx: SessionCommandContext) {
function ensureCommandSession(sessionId: string, command: ParsedSessionCommand, ctx: SessionCommandContext) {
if (getSession(sessionId)) return
createSession({
id: sessionId,
profile: ctx.profile,
source: 'cli',
model: ctx.model,
title: 'Bridge command',
title: buildCommandSessionTitle(command),
})
}
function buildCommandSessionTitle(command: ParsedSessionCommand): string {
const prefix = `[${command.rawName}]`
const args = command.args.replace(/\s+/g, ' ').trim()
return args ? `${prefix} ${args}`.slice(0, 120) : prefix
}
function persistCommandMessage(sessionId: string, state: SessionState, content: string) {
const now = Math.floor(Date.now() / 1000)
const id = addMessage({
+30
View File
@@ -122,6 +122,36 @@ describe('plan session command', () => {
expect(namespaceEmit).not.toHaveBeenCalledWith('session.command', expect.anything())
})
it('creates a new slash-command session with a command-derived title', async () => {
getSessionMock.mockReturnValueOnce(null)
const state = { messages: [], isWorking: false, events: [], queue: [] }
const { bridge, nsp, runQueuedItem, sessionMap, socket } = makeContext(state, {
handled: true,
type: 'goal',
action: 'set',
message: 'Goal set.',
kickoff_prompt: 'build a todo app',
})
const { handleSessionCommand, parseSessionCommand } = await import('../../packages/server/src/services/hermes/run-chat/session-command')
const command = parseSessionCommand('/goal build a todo app')!
await handleSessionCommand('session-1', command, {
nsp: nsp as any,
socket: socket as any,
sessionMap,
bridge: bridge as any,
profile: 'default',
runQueuedItem,
})
expect(createSessionMock).toHaveBeenCalledWith(expect.objectContaining({
id: 'session-1',
profile: 'default',
source: 'cli',
title: '[goal] build a todo app',
}))
})
it('starts an idle /skill command with expanded storage and visible command display', async () => {
const state = { messages: [], isWorking: false, events: [], queue: [] }
const { bridge, namespaceEmit, nsp, runQueuedItem, sessionMap, socket } = makeContext(state, {