feat(ui): add trajectory inspection ledger
This commit is contained in:
@@ -72,8 +72,8 @@ export function apply(ctx: Context): void {
|
||||
},
|
||||
}), 'ui-conversation: input standard-kit provider')
|
||||
|
||||
// Resident current-session-optional shell. It owns the stable Hero/composer
|
||||
// frame while strict session slots fill only their session-bound regions.
|
||||
// Resident current-session-optional shell. It constructs the stable
|
||||
// composer frame; the strict session child decides whether Chat mounts it.
|
||||
slots.register({
|
||||
name: 'conversation',
|
||||
children: {
|
||||
@@ -106,8 +106,8 @@ export function apply(ctx: Context): void {
|
||||
}),
|
||||
}, ConversationRoot)
|
||||
|
||||
// The strict session subtree owns only per-session store and view content;
|
||||
// the resident parent keeps Hero and composer layout identity stable.
|
||||
// The strict session subtree owns the per-session store and view content;
|
||||
// the resident parent supplies the composer node through owner props.
|
||||
slots.register({
|
||||
name: 'conversation.session',
|
||||
children: { 'conversation.view': { kind: 'list', scope: 'session' } },
|
||||
|
||||
@@ -107,6 +107,8 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
|
||||
|
||||
/** Owner share of the strict session content seat. */
|
||||
export interface ConversationSessionOwnerProps {
|
||||
/** Composer chain assembled by the resident parent; only Chat mounts it. */
|
||||
composer: ReactNode
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -74,6 +74,11 @@ export function ConversationRoot({
|
||||
{inputBar}
|
||||
</div>
|
||||
)
|
||||
const composer = renderSlotChain(
|
||||
'conversation.composer',
|
||||
{ interactions: pending },
|
||||
{ fallback: composerBar, overlay: true },
|
||||
)
|
||||
|
||||
return (
|
||||
<div className={css.root} data-phase={hero ? 'hero' : 'active'}>
|
||||
@@ -81,12 +86,9 @@ export function ConversationRoot({
|
||||
renders no chrome while blank but owns the draft-persistence mirror
|
||||
bind — unmounting it in the hero would lose pre-first-send text on
|
||||
a refresh or scope rebuild. */}
|
||||
{sessionId !== undefined && renderSlot('conversation.session', {})}
|
||||
{renderSlotChain(
|
||||
'conversation.composer',
|
||||
{ interactions: pending },
|
||||
{ fallback: composerBar, overlay: true },
|
||||
)}
|
||||
{sessionId !== undefined
|
||||
? renderSlot('conversation.session', { composer })
|
||||
: composer}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/** Strict per-session conversation content: header, view ring, and chat store bindings. */
|
||||
|
||||
import { useEffect, useSyncExternalStore } from 'react'
|
||||
import { Fragment, useEffect, useSyncExternalStore } 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'
|
||||
@@ -24,7 +24,7 @@ function deriveAncestry(list: SessionListState, id: SessionId): readonly Session
|
||||
|
||||
export function ConversationSession({
|
||||
sessionId, useSession, useSessions, useInput, inputActions, useStore, actions,
|
||||
renderSlot, views, bindDraftMirror, open,
|
||||
renderSlot, views, bindDraftMirror, open, composer,
|
||||
}: ConversationSessionProps) {
|
||||
useSyncExternalStore(views.subscribe, views.version)
|
||||
const tabs = views.list()
|
||||
@@ -45,11 +45,11 @@ export function ConversationSession({
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [inputActions])
|
||||
|
||||
if (blank && composerPhase === 'blank') return null
|
||||
const blankHero = blank && composerPhase === 'blank'
|
||||
|
||||
return (
|
||||
<>
|
||||
<header className={css.header}>
|
||||
{!blankHero && <header className={css.header}>
|
||||
<div className={css.crumbRow}>
|
||||
<nav className={css.crumbs} aria-label="Session hierarchy">
|
||||
{ancestry.map((summary, index) => {
|
||||
@@ -88,10 +88,11 @@ export function ConversationSession({
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</header>
|
||||
<div className={css.viewArea}>
|
||||
</header>}
|
||||
{!blankHero && <div className={css.viewArea}>
|
||||
{active !== undefined && renderSlot('conversation.view', {}, { only: active.id })}
|
||||
</div>
|
||||
</div>}
|
||||
{(blankHero || active?.id === 'chat') && <Fragment key="composer">{composer}</Fragment>}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user