diff --git a/apps/desktop/src/app/chat/composer/rich-editor.ts b/apps/desktop/src/app/chat/composer/rich-editor.ts
index 71491b87496d..e3ebe3dffdfd 100644
--- a/apps/desktop/src/app/chat/composer/rich-editor.ts
+++ b/apps/desktop/src/app/chat/composer/rich-editor.ts
@@ -15,6 +15,7 @@ import {
type SlashChipKind,
slashIconElement
} from '@/components/assistant-ui/directive-text'
+import { sessionRefFallbackLabel } from '@/lib/session-link-title'
export const RICH_INPUT_SLOT = 'composer-rich-input'
@@ -59,7 +60,9 @@ export function refChipHtml(kind: string, rawValue: string, displayLabel?: strin
const id = unquoteRef(rawValue)
const text = `@${kind}:${quoteRefValue(id)}`
- return `${directiveIconSvg(kind)}${escapeHtml(displayLabel || refLabel(id))}`
+ const label = displayLabel || (kind === 'session' ? sessionRefFallbackLabel(id) : refLabel(id))
+
+ return `${directiveIconSvg(kind)}${escapeHtml(label)}`
}
export function refChipElement(kind: string, rawValue: string, displayLabel?: string) {
@@ -74,7 +77,7 @@ export function refChipElement(kind: string, rawValue: string, displayLabel?: st
chip.dataset.refKind = kind
chip.className = DIRECTIVE_CHIP_CLASS
label.className = 'truncate'
- label.textContent = displayLabel || refLabel(id)
+ label.textContent = displayLabel || (kind === 'session' ? sessionRefFallbackLabel(id) : refLabel(id))
chip.append(directiveIconElement(kind), label)
return chip
diff --git a/apps/desktop/src/components/assistant-ui/directive-text.test.ts b/apps/desktop/src/components/assistant-ui/directive-text.test.ts
index 60c89f18b1e4..36ab54d743e7 100644
--- a/apps/desktop/src/components/assistant-ui/directive-text.test.ts
+++ b/apps/desktop/src/components/assistant-ui/directive-text.test.ts
@@ -36,4 +36,14 @@ describe('hermesDirectiveFormatter.parse', () => {
{ kind: 'text', text: ' the entry point' }
])
})
+
+ it('parses session links with profile/id values', () => {
+ const segments = hermesDirectiveFormatter.parse('see @session:work/20260101_abc123 next')
+
+ expect(segments).toEqual([
+ { kind: 'text', text: 'see ' },
+ { kind: 'mention', type: 'session', label: '20260101…', id: 'work/20260101_abc123' },
+ { kind: 'text', text: ' next' }
+ ])
+ })
})
diff --git a/apps/desktop/src/components/assistant-ui/directive-text.tsx b/apps/desktop/src/components/assistant-ui/directive-text.tsx
index ffa63a7b8877..e1a83f1c4c0a 100644
--- a/apps/desktop/src/components/assistant-ui/directive-text.tsx
+++ b/apps/desktop/src/components/assistant-ui/directive-text.tsx
@@ -8,6 +8,7 @@ import { Fragment, useEffect, useMemo, useState } from 'react'
import { ZoomableImage } from '@/components/chat/zoomable-image'
import { extractEmbeddedImages } from '@/lib/embedded-images'
import { gatewayMediaDataUrl, isRemoteGateway } from '@/lib/media'
+import { sessionRefFallbackLabel, useSessionLinkTitle } from '@/lib/session-link-title'
const HERMES_REF_TYPES = ['file', 'folder', 'url', 'image', 'tool', 'line', 'terminal', 'session'] as const
type HermesRefType = (typeof HERMES_REF_TYPES)[number]
@@ -40,11 +41,7 @@ const ICON_PATHS: Record = {
tool: ['M7 10h3v-3l-3.5 -3.5a6 6 0 0 1 8 8l6 6a2 2 0 0 1 -3 3l-6 -6a6 6 0 0 1 -8 -8l3.5 3.5'],
line: ['M5 9l14 0', 'M5 15l14 0', 'M11 4l-4 16', 'M17 4l-4 16'],
terminal: ['M5 7l5 5l-5 5', 'M12 19l7 0'],
- session: [
- 'M8 9h8',
- 'M8 13h6',
- 'M18 4a3 3 0 0 1 3 3v8a3 3 0 0 1 -3 3h-5l-5 3v-3h-2a3 3 0 0 1 -3 -3v-8a3 3 0 0 1 3 -3z'
- ]
+ session: ['M4 4h16v2.172a2 2 0 0 1 -.586 1.414l-4.414 4.414v7l-6 2v-8.5l-4.48 -4.928a2 2 0 0 1 -.52 -1.345v-2.227']
}
const ICON_FALLBACK = ['M8 12a4 4 0 1 0 8 0a4 4 0 1 0 -8 0', 'M16 12v1.5a2.5 2.5 0 0 0 5 0v-1.5a9 9 0 1 0 -5.5 8.28']
@@ -314,12 +311,8 @@ function shortLabel(type: HermesRefType, id: string): string {
}
}
- // `@session:/` — show a short id; the composer chip carries the
- // friendly title, but once sent the wire form only has the id.
if (type === 'session') {
- const sid = id.split('/').filter(Boolean).pop() || id
-
- return sid.length > 10 ? `${sid.slice(0, 8)}…` : sid
+ return sessionRefFallbackLabel(id)
}
const tail = id.split(/[\\/]/).filter(Boolean).pop()
@@ -368,7 +361,9 @@ export function DirectiveContent({ text }: { text: string }) {
{segments.map((segment, index) =>
segment.kind === 'text' ? (
{segment.text}
- ) : segment.type === 'image' ? null : (
+ ) : segment.type === 'image' ? null : segment.type === 'session' ? (
+
+ ) : (
)
)}
@@ -451,6 +446,15 @@ const DirectiveImage: FC<{ id: string; label: string }> = ({ id, label }) => {
)
}
+const SessionDirectiveChip: FC<{
+ label: string
+ id: string
+}> = ({ label, id }) => {
+ const resolved = useSessionLinkTitle(id, label)
+
+ return
+}
+
const DirectiveChip: FC<{
type: string
label: string