feat: revert crumbs navigation for subagents
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
- banner:
|
- banner:
|
||||||
- 'heading "Using ONE run_code program: run" [level=1]'
|
- navigation "Session hierarchy":
|
||||||
|
- 'button "Using ONE run_code program: run" [disabled]'
|
||||||
- tablist:
|
- tablist:
|
||||||
- tab "Chat" [selected]
|
- tab "Chat" [selected]
|
||||||
- tab "Trajectory"
|
- tab "Trajectory"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
- banner:
|
- banner:
|
||||||
- heading "Use only Cordis tools. First" [level=1]
|
- navigation "Session hierarchy":
|
||||||
|
- button "Use only Cordis tools. First" [disabled]
|
||||||
- tablist:
|
- tablist:
|
||||||
- tab "Chat" [selected]
|
- tab "Chat" [selected]
|
||||||
- tab "Trajectory"
|
- tab "Trajectory"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
- banner:
|
- banner:
|
||||||
- heading "Use the bash tool to" [level=1]
|
- navigation "Session hierarchy":
|
||||||
|
- button "Use the bash tool to" [disabled]
|
||||||
- tablist:
|
- tablist:
|
||||||
- tab "Chat" [selected]
|
- tab "Chat" [selected]
|
||||||
- tab "Trajectory"
|
- tab "Trajectory"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
- banner:
|
- banner:
|
||||||
- heading "Reply with the single word" [level=1]
|
- navigation "Session hierarchy":
|
||||||
|
- button "Reply with the single word" [disabled]
|
||||||
- tablist:
|
- tablist:
|
||||||
- tab "Chat" [selected]
|
- tab "Chat" [selected]
|
||||||
- tab "Trajectory"
|
- tab "Trajectory"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
- banner:
|
- banner:
|
||||||
- heading "Reply with a one-sentence description" [level=1]
|
- navigation "Session hierarchy":
|
||||||
|
- button "Reply with a one-sentence description" [disabled]
|
||||||
- tablist:
|
- tablist:
|
||||||
- tab "Chat" [selected]
|
- tab "Chat" [selected]
|
||||||
- tab "Trajectory"
|
- tab "Trajectory"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
- banner:
|
- banner:
|
||||||
- heading "Reply with a one-sentence description" [level=1]
|
- navigation "Session hierarchy":
|
||||||
|
- button "Reply with a one-sentence description" [disabled]
|
||||||
- tablist:
|
- tablist:
|
||||||
- tab "Chat" [selected]
|
- tab "Chat" [selected]
|
||||||
- tab "Trajectory"
|
- tab "Trajectory"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
- banner:
|
- banner:
|
||||||
- heading "Reply with a one-sentence description" [level=1]
|
- navigation "Session hierarchy":
|
||||||
|
- button "Reply with a one-sentence description" [disabled]
|
||||||
- tablist:
|
- tablist:
|
||||||
- tab "Chat" [selected]
|
- tab "Chat" [selected]
|
||||||
- tab "Trajectory"
|
- tab "Trajectory"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
- banner:
|
- banner:
|
||||||
- heading "Reply with a one-sentence description" [level=1]
|
- navigation "Session hierarchy":
|
||||||
|
- button "Reply with a one-sentence description" [disabled]
|
||||||
- tablist:
|
- tablist:
|
||||||
- tab "Chat" [selected]
|
- tab "Chat" [selected]
|
||||||
- tab "Trajectory"
|
- tab "Trajectory"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
- banner:
|
- banner:
|
||||||
- heading "Use the read tool twice" [level=1]
|
- navigation "Session hierarchy":
|
||||||
|
- button "Use the read tool twice" [disabled]
|
||||||
- tablist:
|
- tablist:
|
||||||
- tab "Chat" [selected]
|
- tab "Chat" [selected]
|
||||||
- tab "Trajectory"
|
- tab "Trajectory"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
- banner:
|
- banner:
|
||||||
- 'heading "Plan a small change: add" [level=1]'
|
- navigation "Session hierarchy":
|
||||||
|
- 'button "Plan a small change: add" [disabled]'
|
||||||
- tablist:
|
- tablist:
|
||||||
- tab "Chat" [selected]
|
- tab "Chat" [selected]
|
||||||
- tab "Trajectory"
|
- tab "Trajectory"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
- banner:
|
- banner:
|
||||||
- heading "Use the ask_user_question tool to" [level=1]
|
- navigation "Session hierarchy":
|
||||||
|
- button "Use the ask_user_question tool to" [disabled]
|
||||||
- tablist:
|
- tablist:
|
||||||
- tab "Chat" [selected]
|
- tab "Chat" [selected]
|
||||||
- tab "Trajectory"
|
- tab "Trajectory"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
- banner:
|
- banner:
|
||||||
- heading "Reply with a one-sentence description" [level=1]
|
- navigation "Session hierarchy":
|
||||||
|
- button "Reply with a one-sentence description" [disabled]
|
||||||
- tablist:
|
- tablist:
|
||||||
- tab "Chat" [selected]
|
- tab "Chat" [selected]
|
||||||
- tab "Trajectory"
|
- tab "Trajectory"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
- banner:
|
- banner:
|
||||||
- heading "Reply with a one-sentence description" [level=1]
|
- navigation "Session hierarchy":
|
||||||
|
- button "Reply with a one-sentence description" [disabled]
|
||||||
- tablist:
|
- tablist:
|
||||||
- tab "Chat" [selected]
|
- tab "Chat" [selected]
|
||||||
- tab "Trajectory"
|
- tab "Trajectory"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
- banner:
|
- banner:
|
||||||
- heading "Reply with a one-sentence description" [level=1]
|
- navigation "Session hierarchy":
|
||||||
|
- button "Reply with a one-sentence description" [disabled]
|
||||||
- tablist:
|
- tablist:
|
||||||
- tab "Chat" [selected]
|
- tab "Chat" [selected]
|
||||||
- tab "Trajectory"
|
- tab "Trajectory"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
- banner:
|
- banner:
|
||||||
- heading "Reply with a one-sentence description" [level=1]
|
- navigation "Session hierarchy":
|
||||||
|
- button "Reply with a one-sentence description" [disabled]
|
||||||
- tablist:
|
- tablist:
|
||||||
- tab "Chat" [selected]
|
- tab "Chat" [selected]
|
||||||
- tab "Trajectory"
|
- tab "Trajectory"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
- banner:
|
- banner:
|
||||||
- heading "Use the read tool twice" [level=1]
|
- navigation "Session hierarchy":
|
||||||
|
- button "Use the read tool twice" [disabled]
|
||||||
- tablist:
|
- tablist:
|
||||||
- tab "Chat" [selected]
|
- tab "Chat" [selected]
|
||||||
- tab "Trajectory"
|
- tab "Trajectory"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
- banner:
|
- banner:
|
||||||
- heading "Use the read tool twice" [level=1]
|
- navigation "Session hierarchy":
|
||||||
|
- button "Use the read tool twice" [disabled]
|
||||||
- tablist:
|
- tablist:
|
||||||
- tab "Chat" [selected]
|
- tab "Chat" [selected]
|
||||||
- tab "Trajectory"
|
- tab "Trajectory"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
- banner:
|
- banner:
|
||||||
- heading "Use the ask_user_question tool to" [level=1]
|
- navigation "Session hierarchy":
|
||||||
|
- button "Use the ask_user_question tool to" [disabled]
|
||||||
- tablist:
|
- tablist:
|
||||||
- tab "Chat" [selected]
|
- tab "Chat" [selected]
|
||||||
- tab "Trajectory"
|
- tab "Trajectory"
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
- banner:
|
- banner:
|
||||||
- heading "Use the ask_user_question tool to" [level=1]
|
- navigation "Session hierarchy":
|
||||||
|
- button "Use the ask_user_question tool to" [disabled]
|
||||||
- tablist:
|
- tablist:
|
||||||
- tab "Chat" [selected]
|
- tab "Chat" [selected]
|
||||||
- tab "Trajectory"
|
- tab "Trajectory"
|
||||||
|
|||||||
@@ -1,5 +1,8 @@
|
|||||||
- banner:
|
- banner:
|
||||||
- heading "event-sourcing researcher" [level=1]
|
- navigation "Session hierarchy":
|
||||||
|
- button "Ask a research subagent to"
|
||||||
|
- text: /
|
||||||
|
- button "event-sourcing researcher" [disabled]
|
||||||
- button "1 个子代理":
|
- button "1 个子代理":
|
||||||
- text: 1 个子代理
|
- text: 1 个子代理
|
||||||
- img
|
- img
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
- banner:
|
- banner:
|
||||||
- heading "Use web_search to search exactly" [level=1]
|
- navigation "Session hierarchy":
|
||||||
|
- button "Use web_search to search exactly" [disabled]
|
||||||
- tablist:
|
- tablist:
|
||||||
- tab "Chat" [selected]
|
- tab "Chat" [selected]
|
||||||
- tab "Trajectory"
|
- tab "Trajectory"
|
||||||
|
|||||||
@@ -165,6 +165,7 @@ export function apply(ctx: Context): void {
|
|||||||
// the resident parent keeps Hero and composer layout identity stable.
|
// the resident parent keeps Hero and composer layout identity stable.
|
||||||
slots.register({
|
slots.register({
|
||||||
name: 'conversation.session',
|
name: 'conversation.session',
|
||||||
|
locale: NS,
|
||||||
children: {
|
children: {
|
||||||
'conversation.view': { kind: 'list', scope: 'session' },
|
'conversation.view': { kind: 'list', scope: 'session' },
|
||||||
'conversation.session.header.actions': { 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'),
|
version: () => slots.getVersion('conversation.view'),
|
||||||
},
|
},
|
||||||
bindDraftMirror: write => inputHub.shell(sessionId).bindMirror(write),
|
bindDraftMirror: write => inputHub.shell(sessionId).bindMirror(write),
|
||||||
|
open: (id) => { sessions.open(id) },
|
||||||
}),
|
}),
|
||||||
}, ConversationSession)
|
}, ConversationSession)
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import type { ReactNode, RefObject } from 'react'
|
|||||||
import type {
|
import type {
|
||||||
InjectFace, MaybeSnapshotSelectorHook, PropsLocale, PropsRenderSlots, PropsRuntime, PropsStore, SnapshotSelectorHook,
|
InjectFace, MaybeSnapshotSelectorHook, PropsLocale, PropsRenderSlots, PropsRuntime, PropsStore, SnapshotSelectorHook,
|
||||||
} from '@deepseek-ai/dsh-client-ui-slots'
|
} 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 {} from '@deepseek-ai/dsh-client-ui-layout/client'
|
||||||
import type { ComposerKeyboard, EditSelection, InputActions, InputNotice, InputState } from '../input/contract.ts'
|
import type { ComposerKeyboard, EditSelection, InputActions, InputNotice, InputState } from '../input/contract.ts'
|
||||||
import type { createChatStore } from '../stores.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. */
|
/** Bind the input machine's draft persistence mirror to the session store. */
|
||||||
bindDraftMirror: (write: (text: string) => void) => () => void
|
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'>
|
& PropsRenderSlots<'conversation.view' | 'conversation.session.header.actions'>
|
||||||
& PropsStore<ChatStore>
|
& PropsStore<ChatStore>
|
||||||
& ConversationSessionInjected
|
& ConversationSessionInjected
|
||||||
|
& PropsLocale<'conversation'>
|
||||||
|
|
||||||
/** The pending approval carrier the owner dispatches into the composer chain. */
|
/** The pending approval carrier the owner dispatches into the composer chain. */
|
||||||
export type ApprovalWait = PendingWait<'approval'>
|
export type ApprovalWait = PendingWait<'approval'>
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ export const zh = {
|
|||||||
'access.confirm.enable': '启用 Full access',
|
'access.confirm.enable': '启用 Full access',
|
||||||
'hero.headline': '开始构建吧',
|
'hero.headline': '开始构建吧',
|
||||||
'hero.chooseWorkspace': '选择工作区',
|
'hero.chooseWorkspace': '选择工作区',
|
||||||
|
'session.hierarchy': '会话层级',
|
||||||
'details.title': '详情',
|
'details.title': '详情',
|
||||||
'details.close': '关闭详情',
|
'details.close': '关闭详情',
|
||||||
'details.empty': '点击消息流中的工具行查看详情',
|
'details.empty': '点击消息流中的工具行查看详情',
|
||||||
@@ -129,6 +130,7 @@ export const en = {
|
|||||||
'access.confirm.enable': 'Enable Full access',
|
'access.confirm.enable': 'Enable Full access',
|
||||||
'hero.headline': 'Let\'s start building',
|
'hero.headline': 'Let\'s start building',
|
||||||
'hero.chooseWorkspace': 'Choose workspace',
|
'hero.chooseWorkspace': 'Choose workspace',
|
||||||
|
'session.hierarchy': 'Session hierarchy',
|
||||||
'details.title': 'Details',
|
'details.title': 'Details',
|
||||||
'details.close': 'Close details',
|
'details.close': 'Close details',
|
||||||
'details.empty': 'Click a tool row in the message flow to view its details',
|
'details.empty': 'Click a tool row in the message flow to view its details',
|
||||||
|
|||||||
@@ -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;
|
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
|
this fills its cell. Figma: Header 39:27730 (83px two-row), tabs 13px with
|
||||||
a 3px active bar. */
|
a 3px active bar. */
|
||||||
@@ -26,23 +26,55 @@
|
|||||||
.titleRow {
|
.titleRow {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: space-between;
|
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
min-height: 32px;
|
min-height: 32px;
|
||||||
}
|
}
|
||||||
|
.crumbs {
|
||||||
.sessionTitle {
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
max-width: 100%;
|
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
margin: 0;
|
white-space: nowrap;
|
||||||
padding: 4px 8px;
|
}
|
||||||
|
|
||||||
|
.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;
|
font-size: 14px;
|
||||||
line-height: 20px;
|
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;
|
text-overflow: ellipsis;
|
||||||
white-space: nowrap;
|
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 {
|
.headerActions {
|
||||||
|
|||||||
@@ -2,21 +2,35 @@
|
|||||||
|
|
||||||
import { useEffect, useSyncExternalStore, type ReactNode } from 'react'
|
import { useEffect, useSyncExternalStore, type ReactNode } from 'react'
|
||||||
import clsx from 'clsx'
|
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 type { ConversationSessionSlotProps } from '../contract/slots.ts'
|
||||||
import css from './ConversationRoot.module.css'
|
import css from './ConversationRoot.module.css'
|
||||||
|
|
||||||
/** Full props composed from the strict session slot contract. */
|
/** Full props composed from the strict session slot contract. */
|
||||||
export type ConversationSessionProps = ConversationSessionSlotProps
|
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({
|
export function ConversationSession({
|
||||||
sessionId, useSession, useSessions, useInput, inputActions, useStore, actions,
|
sessionId, useSession, useSessions, useInput, inputActions, useStore, actions,
|
||||||
renderSlot, views, bindDraftMirror, wrapActiveBody,
|
renderSlot, views, bindDraftMirror, open, wrapActiveBody, t
|
||||||
}: ConversationSessionProps) {
|
}: ConversationSessionProps) {
|
||||||
useSyncExternalStore(views.subscribe, views.version)
|
useSyncExternalStore(views.subscribe, views.version)
|
||||||
const tabs = views.list()
|
const tabs = views.list()
|
||||||
const activeId = useStore(s => s.view) ?? 'chat'
|
const activeId = useStore(s => s.view) ?? 'chat'
|
||||||
const active = tabs.find(view => view.id === activeId) ?? tabs[0]
|
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 composerPhase = useSession(s => s.composerPhase)
|
||||||
const blank = useSession(s => s.blank)
|
const blank = useSession(s => s.blank)
|
||||||
const inputState = useInput(s => s)
|
const inputState = useInput(s => s)
|
||||||
@@ -56,7 +70,25 @@ export function ConversationSession({
|
|||||||
{!hideChrome && (
|
{!hideChrome && (
|
||||||
<>
|
<>
|
||||||
<div className={css.titleRow}>
|
<div className={css.titleRow}>
|
||||||
<h1 className={css.sessionTitle}>{title}</h1>
|
<nav className={css.crumbs} aria-label={t('session.hierarchy')}>
|
||||||
|
{ancestry.map((summary, index) => {
|
||||||
|
const last = index === ancestry.length - 1
|
||||||
|
return (
|
||||||
|
<span key={summary.id} className={css.crumbSeg}>
|
||||||
|
{index > 0 && <span className={css.crumbSep}>/</span>}
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
className={clsx(css.crumb, last && css.crumbCurrent)}
|
||||||
|
disabled={last}
|
||||||
|
onClick={() => { open(summary.id) }}
|
||||||
|
>
|
||||||
|
{summary.displayTitle}
|
||||||
|
</button>
|
||||||
|
</span>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
{ancestry.length === 0 && <span className={css.crumbCurrent}>{sessionId}</span>}
|
||||||
|
</nav>
|
||||||
<div className={css.headerActions}>
|
<div className={css.headerActions}>
|
||||||
{renderSlot('conversation.session.header.actions', {})}
|
{renderSlot('conversation.session.header.actions', {})}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ function mount(
|
|||||||
const useInput = bindSnapshotSelector(wiring.state)
|
const useInput = bindSnapshotSelector(wiring.state)
|
||||||
const inputActions = wiring.actions
|
const inputActions = wiring.actions
|
||||||
const stop = vi.fn()
|
const stop = vi.fn()
|
||||||
|
const open = vi.fn()
|
||||||
const slotCalls: string[] = []
|
const slotCalls: string[] = []
|
||||||
let pickerOwner: unknown
|
let pickerOwner: unknown
|
||||||
const renderSlot = ((key: string, owner: object, opts?: { only?: string }) => {
|
const renderSlot = ((key: string, owner: object, opts?: { only?: string }) => {
|
||||||
@@ -139,6 +140,8 @@ function mount(
|
|||||||
version: () => 1,
|
version: () => 1,
|
||||||
}}
|
}}
|
||||||
bindDraftMirror={write => wiring.bindMirror(write)}
|
bindDraftMirror={write => wiring.bindMirror(write)}
|
||||||
|
open={open}
|
||||||
|
t={t}
|
||||||
{...owner}
|
{...owner}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import type {
|
|||||||
import type { ConvViewProps, ViewTab } from '@deepseek-ai/dsh-client-ui-conversation/client'
|
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 { 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 { 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, inject } from '@deepseek-ai/dsh-client-ui-trajectory/client'
|
||||||
import { apply as nodeApply } from '@deepseek-ai/dsh-client-ui-trajectory'
|
import { apply as nodeApply } from '@deepseek-ai/dsh-client-ui-trajectory'
|
||||||
import type { TrajectoryTurnModel } from '../src/client/layout.ts'
|
import type { TrajectoryTurnModel } from '../src/client/layout.ts'
|
||||||
@@ -35,6 +36,11 @@ import { deriveTrajectoryTimeline } from '../src/client/timeline.ts'
|
|||||||
|
|
||||||
const SID = 's1' as SessionId
|
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<string, string>)[key] ?? key
|
||||||
afterEach(cleanup)
|
afterEach(cleanup)
|
||||||
// The chat store persists under its declared key; clear so one case's active
|
// The chat store persists under its declared key; clear so one case's active
|
||||||
// view cannot rehydrate into the next.
|
// view cannot rehydrate into the next.
|
||||||
@@ -213,6 +219,7 @@ function mount(slots: SlotsService, nodes: ConversationSnapshot['nodes'] = NODES
|
|||||||
return render(
|
return render(
|
||||||
<ConversationSession
|
<ConversationSession
|
||||||
sessionId={SID}
|
sessionId={SID}
|
||||||
|
t={tConversation}
|
||||||
SessionProvider={({ children }) => children(SID)}
|
SessionProvider={({ children }) => children(SID)}
|
||||||
useSession={useSession}
|
useSession={useSession}
|
||||||
useSessions={emptySessions()}
|
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}
|
useInput={bindSnapshotSelector(createSnapshotStore({ draft: '', draftRev: 0, phase: 'plain', queue: [] })) as never}
|
||||||
inputActions={{ setDraft: vi.fn(), submit: vi.fn() }}
|
inputActions={{ setDraft: vi.fn(), submit: vi.fn() }}
|
||||||
bindDraftMirror={() => () => {}}
|
bindDraftMirror={() => () => {}}
|
||||||
|
open={vi.fn()}
|
||||||
/>,
|
/>,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user