From 5d56019d22a51f4125c5f54003ebdb75395f2f11 Mon Sep 17 00:00:00 2001 From: imccyu Date: Sat, 1 Aug 2026 14:30:16 +0800 Subject: [PATCH] feat: revert crumbs navigation for subagents --- .../snapshots/code-mode-round/ui.expected.md | 3 +- .../cordis-tool-round/ui.expected.md | 3 +- .../snapshots/fresh-round-trip/ui.expected.md | 3 +- .../lifecycle-chrome/reloaded.expected.md | 3 +- .../live-interactions/cancel.expected.md | 3 +- .../live-interactions/error-auth.expected.md | 3 +- .../live-interactions/loading.expected.md | 3 +- .../live-interactions/retry.expected.md | 3 +- .../snapshots/message-actions/ui.expected.md | 3 +- .../plan-review/approved.expected.md | 3 +- .../question-composer/answered.expected.md | 3 +- .../queue-actions/collapsed.expected.md | 3 +- .../queue-actions/editing.expected.md | 3 +- .../queue-actions/preserved.expected.md | 3 +- .../snapshots/queue-actions/ui.expected.md | 3 +- .../seeded-history/command-row.expected.md | 3 +- .../snapshots/seeded-history/ui.expected.md | 3 +- .../snapshots/steering/mid-steer.expected.md | 3 +- .../snapshots/steering/settled.expected.md | 3 +- .../subagent-conversation/ui.expected.md | 5 +- .../snapshots/web-search-round/ui.expected.md | 3 +- .../ui-conversation/src/client/apply.ts | 2 + .../src/client/contract/slots.ts | 5 +- .../ui-conversation/src/client/locales.ts | 2 + .../skeleton/ConversationRoot.module.css | 50 +++++++++++++++---- .../client/skeleton/ConversationSession.tsx | 38 ++++++++++++-- .../ui-conversation/tests/skeleton.spec.tsx | 3 ++ .../client/ui-trajectory/tests/views.spec.tsx | 8 +++ 28 files changed, 139 insertions(+), 34 deletions(-) diff --git a/apps/web/tests/snapshots/code-mode-round/ui.expected.md b/apps/web/tests/snapshots/code-mode-round/ui.expected.md index 4120cf599b..8f4c7e5bf2 100644 --- a/apps/web/tests/snapshots/code-mode-round/ui.expected.md +++ b/apps/web/tests/snapshots/code-mode-round/ui.expected.md @@ -1,5 +1,6 @@ - banner: - - 'heading "Using ONE run_code program: run" [level=1]' + - navigation "Session hierarchy": + - 'button "Using ONE run_code program: run" [disabled]' - tablist: - tab "Chat" [selected] - tab "Trajectory" diff --git a/apps/web/tests/snapshots/cordis-tool-round/ui.expected.md b/apps/web/tests/snapshots/cordis-tool-round/ui.expected.md index f0630eccbe..e4d5ac8426 100644 --- a/apps/web/tests/snapshots/cordis-tool-round/ui.expected.md +++ b/apps/web/tests/snapshots/cordis-tool-round/ui.expected.md @@ -1,5 +1,6 @@ - banner: - - heading "Use only Cordis tools. First" [level=1] + - navigation "Session hierarchy": + - button "Use only Cordis tools. First" [disabled] - tablist: - tab "Chat" [selected] - tab "Trajectory" diff --git a/apps/web/tests/snapshots/fresh-round-trip/ui.expected.md b/apps/web/tests/snapshots/fresh-round-trip/ui.expected.md index d1d71c579c..facb7b58cc 100644 --- a/apps/web/tests/snapshots/fresh-round-trip/ui.expected.md +++ b/apps/web/tests/snapshots/fresh-round-trip/ui.expected.md @@ -1,5 +1,6 @@ - banner: - - heading "Use the bash tool to" [level=1] + - navigation "Session hierarchy": + - button "Use the bash tool to" [disabled] - tablist: - tab "Chat" [selected] - tab "Trajectory" diff --git a/apps/web/tests/snapshots/lifecycle-chrome/reloaded.expected.md b/apps/web/tests/snapshots/lifecycle-chrome/reloaded.expected.md index f2cf47d6ec..5965797c69 100644 --- a/apps/web/tests/snapshots/lifecycle-chrome/reloaded.expected.md +++ b/apps/web/tests/snapshots/lifecycle-chrome/reloaded.expected.md @@ -1,5 +1,6 @@ - banner: - - heading "Reply with the single word" [level=1] + - navigation "Session hierarchy": + - button "Reply with the single word" [disabled] - tablist: - tab "Chat" [selected] - tab "Trajectory" diff --git a/apps/web/tests/snapshots/live-interactions/cancel.expected.md b/apps/web/tests/snapshots/live-interactions/cancel.expected.md index 11a496fd3f..d1e4d2bbef 100644 --- a/apps/web/tests/snapshots/live-interactions/cancel.expected.md +++ b/apps/web/tests/snapshots/live-interactions/cancel.expected.md @@ -1,5 +1,6 @@ - banner: - - heading "Reply with a one-sentence description" [level=1] + - navigation "Session hierarchy": + - button "Reply with a one-sentence description" [disabled] - tablist: - tab "Chat" [selected] - tab "Trajectory" diff --git a/apps/web/tests/snapshots/live-interactions/error-auth.expected.md b/apps/web/tests/snapshots/live-interactions/error-auth.expected.md index e42743a23a..fb9337e978 100644 --- a/apps/web/tests/snapshots/live-interactions/error-auth.expected.md +++ b/apps/web/tests/snapshots/live-interactions/error-auth.expected.md @@ -1,5 +1,6 @@ - banner: - - heading "Reply with a one-sentence description" [level=1] + - navigation "Session hierarchy": + - button "Reply with a one-sentence description" [disabled] - tablist: - tab "Chat" [selected] - tab "Trajectory" diff --git a/apps/web/tests/snapshots/live-interactions/loading.expected.md b/apps/web/tests/snapshots/live-interactions/loading.expected.md index d299f7f96a..a5dfd08fb5 100644 --- a/apps/web/tests/snapshots/live-interactions/loading.expected.md +++ b/apps/web/tests/snapshots/live-interactions/loading.expected.md @@ -1,5 +1,6 @@ - banner: - - heading "Reply with a one-sentence description" [level=1] + - navigation "Session hierarchy": + - button "Reply with a one-sentence description" [disabled] - tablist: - tab "Chat" [selected] - tab "Trajectory" diff --git a/apps/web/tests/snapshots/live-interactions/retry.expected.md b/apps/web/tests/snapshots/live-interactions/retry.expected.md index 150bab2fda..6380eaf5c6 100644 --- a/apps/web/tests/snapshots/live-interactions/retry.expected.md +++ b/apps/web/tests/snapshots/live-interactions/retry.expected.md @@ -1,5 +1,6 @@ - banner: - - heading "Reply with a one-sentence description" [level=1] + - navigation "Session hierarchy": + - button "Reply with a one-sentence description" [disabled] - tablist: - tab "Chat" [selected] - tab "Trajectory" diff --git a/apps/web/tests/snapshots/message-actions/ui.expected.md b/apps/web/tests/snapshots/message-actions/ui.expected.md index fd1aa31c17..bf67498178 100644 --- a/apps/web/tests/snapshots/message-actions/ui.expected.md +++ b/apps/web/tests/snapshots/message-actions/ui.expected.md @@ -1,5 +1,6 @@ - banner: - - heading "Use the read tool twice" [level=1] + - navigation "Session hierarchy": + - button "Use the read tool twice" [disabled] - tablist: - tab "Chat" [selected] - tab "Trajectory" diff --git a/apps/web/tests/snapshots/plan-review/approved.expected.md b/apps/web/tests/snapshots/plan-review/approved.expected.md index d2ac035936..5be3f83247 100644 --- a/apps/web/tests/snapshots/plan-review/approved.expected.md +++ b/apps/web/tests/snapshots/plan-review/approved.expected.md @@ -1,5 +1,6 @@ - banner: - - 'heading "Plan a small change: add" [level=1]' + - navigation "Session hierarchy": + - 'button "Plan a small change: add" [disabled]' - tablist: - tab "Chat" [selected] - tab "Trajectory" diff --git a/apps/web/tests/snapshots/question-composer/answered.expected.md b/apps/web/tests/snapshots/question-composer/answered.expected.md index 08395cd56b..28297569ab 100644 --- a/apps/web/tests/snapshots/question-composer/answered.expected.md +++ b/apps/web/tests/snapshots/question-composer/answered.expected.md @@ -1,5 +1,6 @@ - banner: - - heading "Use the ask_user_question tool to" [level=1] + - navigation "Session hierarchy": + - button "Use the ask_user_question tool to" [disabled] - tablist: - tab "Chat" [selected] - tab "Trajectory" diff --git a/apps/web/tests/snapshots/queue-actions/collapsed.expected.md b/apps/web/tests/snapshots/queue-actions/collapsed.expected.md index d7a5188bac..b9dee060ac 100644 --- a/apps/web/tests/snapshots/queue-actions/collapsed.expected.md +++ b/apps/web/tests/snapshots/queue-actions/collapsed.expected.md @@ -1,5 +1,6 @@ - banner: - - heading "Reply with a one-sentence description" [level=1] + - navigation "Session hierarchy": + - button "Reply with a one-sentence description" [disabled] - tablist: - tab "Chat" [selected] - tab "Trajectory" diff --git a/apps/web/tests/snapshots/queue-actions/editing.expected.md b/apps/web/tests/snapshots/queue-actions/editing.expected.md index 8ae1e69707..3a70840713 100644 --- a/apps/web/tests/snapshots/queue-actions/editing.expected.md +++ b/apps/web/tests/snapshots/queue-actions/editing.expected.md @@ -1,5 +1,6 @@ - banner: - - heading "Reply with a one-sentence description" [level=1] + - navigation "Session hierarchy": + - button "Reply with a one-sentence description" [disabled] - tablist: - tab "Chat" [selected] - tab "Trajectory" diff --git a/apps/web/tests/snapshots/queue-actions/preserved.expected.md b/apps/web/tests/snapshots/queue-actions/preserved.expected.md index 4ef33d18b0..0a43cee68b 100644 --- a/apps/web/tests/snapshots/queue-actions/preserved.expected.md +++ b/apps/web/tests/snapshots/queue-actions/preserved.expected.md @@ -1,5 +1,6 @@ - banner: - - heading "Reply with a one-sentence description" [level=1] + - navigation "Session hierarchy": + - button "Reply with a one-sentence description" [disabled] - tablist: - tab "Chat" [selected] - tab "Trajectory" diff --git a/apps/web/tests/snapshots/queue-actions/ui.expected.md b/apps/web/tests/snapshots/queue-actions/ui.expected.md index 121b7a4ef2..24edb57417 100644 --- a/apps/web/tests/snapshots/queue-actions/ui.expected.md +++ b/apps/web/tests/snapshots/queue-actions/ui.expected.md @@ -1,5 +1,6 @@ - banner: - - heading "Reply with a one-sentence description" [level=1] + - navigation "Session hierarchy": + - button "Reply with a one-sentence description" [disabled] - tablist: - tab "Chat" [selected] - tab "Trajectory" diff --git a/apps/web/tests/snapshots/seeded-history/command-row.expected.md b/apps/web/tests/snapshots/seeded-history/command-row.expected.md index b633d226ea..b916a3add2 100644 --- a/apps/web/tests/snapshots/seeded-history/command-row.expected.md +++ b/apps/web/tests/snapshots/seeded-history/command-row.expected.md @@ -1,5 +1,6 @@ - banner: - - heading "Use the read tool twice" [level=1] + - navigation "Session hierarchy": + - button "Use the read tool twice" [disabled] - tablist: - tab "Chat" [selected] - tab "Trajectory" diff --git a/apps/web/tests/snapshots/seeded-history/ui.expected.md b/apps/web/tests/snapshots/seeded-history/ui.expected.md index 9614446699..a168d5e2a3 100644 --- a/apps/web/tests/snapshots/seeded-history/ui.expected.md +++ b/apps/web/tests/snapshots/seeded-history/ui.expected.md @@ -1,5 +1,6 @@ - banner: - - heading "Use the read tool twice" [level=1] + - navigation "Session hierarchy": + - button "Use the read tool twice" [disabled] - tablist: - tab "Chat" [selected] - tab "Trajectory" diff --git a/apps/web/tests/snapshots/steering/mid-steer.expected.md b/apps/web/tests/snapshots/steering/mid-steer.expected.md index 671e39a351..27b40ef442 100644 --- a/apps/web/tests/snapshots/steering/mid-steer.expected.md +++ b/apps/web/tests/snapshots/steering/mid-steer.expected.md @@ -1,5 +1,6 @@ - banner: - - heading "Use the ask_user_question tool to" [level=1] + - navigation "Session hierarchy": + - button "Use the ask_user_question tool to" [disabled] - tablist: - tab "Chat" [selected] - tab "Trajectory" diff --git a/apps/web/tests/snapshots/steering/settled.expected.md b/apps/web/tests/snapshots/steering/settled.expected.md index f87ec83143..72e28598e5 100644 --- a/apps/web/tests/snapshots/steering/settled.expected.md +++ b/apps/web/tests/snapshots/steering/settled.expected.md @@ -1,5 +1,6 @@ - banner: - - heading "Use the ask_user_question tool to" [level=1] + - navigation "Session hierarchy": + - button "Use the ask_user_question tool to" [disabled] - tablist: - tab "Chat" [selected] - tab "Trajectory" diff --git a/apps/web/tests/snapshots/subagent-conversation/ui.expected.md b/apps/web/tests/snapshots/subagent-conversation/ui.expected.md index 2895b93043..6513bb60e3 100644 --- a/apps/web/tests/snapshots/subagent-conversation/ui.expected.md +++ b/apps/web/tests/snapshots/subagent-conversation/ui.expected.md @@ -1,5 +1,8 @@ - banner: - - heading "event-sourcing researcher" [level=1] + - navigation "Session hierarchy": + - button "Ask a research subagent to" + - text: / + - button "event-sourcing researcher" [disabled] - button "1 个子代理": - text: 1 个子代理 - img diff --git a/apps/web/tests/snapshots/web-search-round/ui.expected.md b/apps/web/tests/snapshots/web-search-round/ui.expected.md index 17ad30b624..4ff674462e 100644 --- a/apps/web/tests/snapshots/web-search-round/ui.expected.md +++ b/apps/web/tests/snapshots/web-search-round/ui.expected.md @@ -1,5 +1,6 @@ - banner: - - heading "Use web_search to search exactly" [level=1] + - navigation "Session hierarchy": + - button "Use web_search to search exactly" [disabled] - tablist: - tab "Chat" [selected] - tab "Trajectory" diff --git a/packages/client/ui-conversation/src/client/apply.ts b/packages/client/ui-conversation/src/client/apply.ts index 67000dff37..625728d4cf 100644 --- a/packages/client/ui-conversation/src/client/apply.ts +++ b/packages/client/ui-conversation/src/client/apply.ts @@ -165,6 +165,7 @@ export function apply(ctx: Context): void { // the resident parent keeps Hero and composer layout identity stable. slots.register({ name: 'conversation.session', + locale: NS, children: { 'conversation.view': { kind: 'list', scope: 'session' }, 'conversation.session.header.actions': { kind: 'list', scope: 'session' }, @@ -177,6 +178,7 @@ export function apply(ctx: Context): void { version: () => slots.getVersion('conversation.view'), }, bindDraftMirror: write => inputHub.shell(sessionId).bindMirror(write), + open: (id) => { sessions.open(id) }, }), }, ConversationSession) diff --git a/packages/client/ui-conversation/src/client/contract/slots.ts b/packages/client/ui-conversation/src/client/contract/slots.ts index f1ba8c8ef1..a6c9d16e61 100644 --- a/packages/client/ui-conversation/src/client/contract/slots.ts +++ b/packages/client/ui-conversation/src/client/contract/slots.ts @@ -3,7 +3,7 @@ import type { ReactNode, RefObject } from 'react' import type { InjectFace, MaybeSnapshotSelectorHook, PropsLocale, PropsRenderSlots, PropsRuntime, PropsStore, SnapshotSelectorHook, } from '@deepseek-ai/dsh-client-ui-slots' -import type { CommandNode, ConversationSnapshot, ObservableSnapshot, PendingInteraction, PendingWait, ToolCallBlock, WorkspaceId } from '@deepseek-ai/dsh-client-runtime/client' +import type { CommandNode, ConversationSnapshot, ObservableSnapshot, PendingInteraction, PendingWait, SessionId, ToolCallBlock, WorkspaceId } from '@deepseek-ai/dsh-client-runtime/client' import type {} from '@deepseek-ai/dsh-client-ui-layout/client' import type { ComposerKeyboard, EditSelection, InputActions, InputNotice, InputState } from '../input/contract.ts' import type { createChatStore } from '../stores.ts' @@ -249,6 +249,8 @@ export interface ConversationSessionInjected { } /** Bind the input machine's draft persistence mirror to the session store. */ bindDraftMirror: (write: (text: string) => void) => () => void + /** Select a real Session through the runtime navigation owner. */ + open: (sessionId: SessionId) => void } /** @@ -360,6 +362,7 @@ export type ConversationSessionSlotProps = & PropsRenderSlots<'conversation.view' | 'conversation.session.header.actions'> & PropsStore & ConversationSessionInjected + & PropsLocale<'conversation'> /** The pending approval carrier the owner dispatches into the composer chain. */ export type ApprovalWait = PendingWait<'approval'> diff --git a/packages/client/ui-conversation/src/client/locales.ts b/packages/client/ui-conversation/src/client/locales.ts index 1bda57660d..76560ca9e4 100644 --- a/packages/client/ui-conversation/src/client/locales.ts +++ b/packages/client/ui-conversation/src/client/locales.ts @@ -30,6 +30,7 @@ export const zh = { 'access.confirm.enable': '启用 Full access', 'hero.headline': '开始构建吧', 'hero.chooseWorkspace': '选择工作区', + 'session.hierarchy': '会话层级', 'details.title': '详情', 'details.close': '关闭详情', 'details.empty': '点击消息流中的工具行查看详情', @@ -129,6 +130,7 @@ export const en = { 'access.confirm.enable': 'Enable Full access', 'hero.headline': 'Let\'s start building', 'hero.chooseWorkspace': 'Choose workspace', + 'session.hierarchy': 'Session hierarchy', 'details.title': 'Details', 'details.close': 'Close details', 'details.empty': 'Click a tool row in the message flow to view its details', diff --git a/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.module.css b/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.module.css index 4c6c09611a..be480eaea2 100644 --- a/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.module.css +++ b/packages/client/ui-conversation/src/client/skeleton/ConversationRoot.module.css @@ -1,4 +1,4 @@ -/* Conversation column skeleton: header (session title + tabs) over the view +/* Conversation column skeleton: header (breadcrumb row only for subagents not fork + tabs) over the view area, composer InputBar at the bottom. Column width/squeeze is layout's; this fills its cell. Figma: Header 39:27730 (83px two-row), tabs 13px with a 3px active bar. */ @@ -26,23 +26,55 @@ .titleRow { display: flex; align-items: center; - justify-content: space-between; gap: 10px; min-height: 32px; } - -.sessionTitle { +.crumbs { + display: flex; + align-items: center; + gap: 4px; min-width: 0; - max-width: 100%; overflow: hidden; - margin: 0; - padding: 4px 8px; + white-space: nowrap; +} + +.crumbSeg { + display: inline-flex; + align-items: center; + gap: 4px; + min-width: 0; +} + +.crumbSep { + /* figma: "/" separators are 14px caption gray (75:7903), one tint lighter than crumb text. */ + color: var(--dsw-alias-label-caption); font-size: 14px; line-height: 20px; - font-weight: 500; - color: var(--dsw-alias-label-primary); +} + +.crumb { + max-width: 220px; + overflow: hidden; + padding: 4px 8px; + border: none; + border-radius: 12px; + background: transparent; + font-size: 14px; + line-height: 20px; + color: var(--dsw-alias-label-tertiary); text-overflow: ellipsis; white-space: nowrap; + cursor: pointer; +} + +.crumb:hover:not(:disabled) { + background: var(--dsw-alias-interactive-bg-hover); +} + +.crumbCurrent { + font-weight: 500; + color: var(--dsw-alias-label-primary); + cursor: default; } .headerActions { diff --git a/packages/client/ui-conversation/src/client/skeleton/ConversationSession.tsx b/packages/client/ui-conversation/src/client/skeleton/ConversationSession.tsx index 7e34cc1b9a..b20f6464eb 100644 --- a/packages/client/ui-conversation/src/client/skeleton/ConversationSession.tsx +++ b/packages/client/ui-conversation/src/client/skeleton/ConversationSession.tsx @@ -2,21 +2,35 @@ import { useEffect, useSyncExternalStore, type ReactNode } from 'react' import clsx from 'clsx' +import { shallowEqual } from '@deepseek-ai/dsh-client-runtime/client' +import type { SessionId, SessionListState, SessionSummary } from '@deepseek-ai/dsh-client-runtime/client' import type { ConversationSessionSlotProps } from '../contract/slots.ts' import css from './ConversationRoot.module.css' /** Full props composed from the strict session slot contract. */ export type ConversationSessionProps = ConversationSessionSlotProps +function deriveAncestry(list: SessionListState, id: SessionId): readonly SessionSummary[] { + const chain: SessionSummary[] = [] + let cursor: SessionId | undefined = id + while (cursor !== undefined) { + const summary: SessionSummary | undefined = list.byId[cursor] + if (summary === undefined || chain.includes(summary)) break + chain.unshift(summary) + cursor = summary.parentId + } + return chain +} + export function ConversationSession({ sessionId, useSession, useSessions, useInput, inputActions, useStore, actions, - renderSlot, views, bindDraftMirror, wrapActiveBody, + renderSlot, views, bindDraftMirror, open, wrapActiveBody, t }: ConversationSessionProps) { useSyncExternalStore(views.subscribe, views.version) const tabs = views.list() const activeId = useStore(s => s.view) ?? 'chat' const active = tabs.find(view => view.id === activeId) ?? tabs[0] - const title = useSessions(s => s.byId[sessionId]?.displayTitle ?? sessionId) + const ancestry = useSessions(s => deriveAncestry(s, sessionId), shallowEqual) const composerPhase = useSession(s => s.composerPhase) const blank = useSession(s => s.blank) const inputState = useInput(s => s) @@ -56,7 +70,25 @@ export function ConversationSession({ {!hideChrome && ( <>
-

{title}

+
{renderSlot('conversation.session.header.actions', {})}
diff --git a/packages/client/ui-conversation/tests/skeleton.spec.tsx b/packages/client/ui-conversation/tests/skeleton.spec.tsx index a117aa58e1..69f94a99fc 100644 --- a/packages/client/ui-conversation/tests/skeleton.spec.tsx +++ b/packages/client/ui-conversation/tests/skeleton.spec.tsx @@ -111,6 +111,7 @@ function mount( const useInput = bindSnapshotSelector(wiring.state) const inputActions = wiring.actions const stop = vi.fn() + const open = vi.fn() const slotCalls: string[] = [] let pickerOwner: unknown const renderSlot = ((key: string, owner: object, opts?: { only?: string }) => { @@ -139,6 +140,8 @@ function mount( version: () => 1, }} bindDraftMirror={write => wiring.bindMirror(write)} + open={open} + t={t} {...owner} /> ) diff --git a/packages/client/ui-trajectory/tests/views.spec.tsx b/packages/client/ui-trajectory/tests/views.spec.tsx index 49d852f349..fca6608950 100644 --- a/packages/client/ui-trajectory/tests/views.spec.tsx +++ b/packages/client/ui-trajectory/tests/views.spec.tsx @@ -23,6 +23,7 @@ import type { import type { ConvViewProps, ViewTab } from '@deepseek-ai/dsh-client-ui-conversation/client' import { ConversationSession, type ConversationSessionProps } from '@deepseek-ai/dsh-client-ui-conversation/src/client/skeleton/ConversationSession.tsx' import { createChatStore } from '@deepseek-ai/dsh-client-ui-conversation/src/client/stores.ts' +import { zh as conversationZh } from '@deepseek-ai/dsh-client-ui-conversation/src/client/locales.ts' import { apply, inject } from '@deepseek-ai/dsh-client-ui-trajectory/client' import { apply as nodeApply } from '@deepseek-ai/dsh-client-ui-trajectory' import type { TrajectoryTurnModel } from '../src/client/layout.ts' @@ -35,6 +36,11 @@ import { deriveTrajectoryTimeline } from '../src/client/timeline.ts' const SID = 's1' as SessionId +// Stub of the conversation package's standard locale seat (this spec mounts +// its ConversationSession chrome); answers from the zh dictionary and falls +// back to the key like the real chain. +const tConversation: ConversationSessionProps['t'] = + key => (conversationZh as Record)[key] ?? key afterEach(cleanup) // The chat store persists under its declared key; clear so one case's active // view cannot rehydrate into the next. @@ -213,6 +219,7 @@ function mount(slots: SlotsService, nodes: ConversationSnapshot['nodes'] = NODES return render( children(SID)} useSession={useSession} useSessions={emptySessions()} @@ -229,6 +236,7 @@ function mount(slots: SlotsService, nodes: ConversationSnapshot['nodes'] = NODES useInput={bindSnapshotSelector(createSnapshotStore({ draft: '', draftRev: 0, phase: 'plain', queue: [] })) as never} inputActions={{ setDraft: vi.fn(), submit: vi.fn() }} bindDraftMirror={() => () => {}} + open={vi.fn()} />, ) }