Merge remote-tracking branch 'origin/master' into worktree/persist-web-theme-settings
# Conflicts: # packages/client/ui-conversation/README.i18n.yaml # packages/client/ui-theme/README.i18n.yaml # packages/host/apiproxy/README.i18n.yaml
This commit is contained in:
@@ -313,6 +313,7 @@ export function apply(ctx: Context): void {
|
||||
children: {
|
||||
'conversation.chat.toolview': { kind: 'keyed', scope: 'session' },
|
||||
'conversation.chat.commandview': { kind: 'keyed', scope: 'session' },
|
||||
'conversation.chat.turnTail': { kind: 'chain', scope: 'session' },
|
||||
},
|
||||
store: chatStore,
|
||||
inject: (sessionId: SessionId, actions: BoundActions<typeof chatStore>): ChatViewInjected => {
|
||||
|
||||
@@ -11,10 +11,11 @@
|
||||
|
||||
import { memo, useMemo } from 'react'
|
||||
import type { AssistantBlock } from '@deepseek-ai/dsh-client-runtime/client'
|
||||
import type { PropsRenderSlots } from '@deepseek-ai/dsh-client-ui-slots'
|
||||
import {
|
||||
IconThinkOutline14, JsonBlock, MarkdownText,
|
||||
} from '@deepseek-ai/dsh-client-ui-primitives'
|
||||
import type { ChatViewSlotProps } from '../contract/slots.ts'
|
||||
import type { ChatViewSlotProps, TurnTailOwnerProps } from '../contract/slots.ts'
|
||||
import { hasContentText } from './chat-flow.ts'
|
||||
import { MessageIconActions } from './MessageIconActions.tsx'
|
||||
import { ToolRow } from './ToolRow.tsx'
|
||||
@@ -40,6 +41,8 @@ export interface AssistantMarkdownProps {
|
||||
seq?: number | undefined
|
||||
/** Fork the session through this finalized message's completed turn when eligible. */
|
||||
onFork?: ((seq: number) => void) | undefined
|
||||
/** Turn-tail slot dispatch share and owner currency; omitted for a mid-turn assistant. */
|
||||
turnTail?: (Pick<PropsRenderSlots<'conversation.chat.turnTail'>, 'renderSlotChain'> & { owner: TurnTailOwnerProps }) | undefined
|
||||
/** The message is not the transcript tail of a completed turn. */
|
||||
forkUnavailable?: boolean | undefined
|
||||
/** The owning view's locale seat, passed down as a plain prop. */
|
||||
@@ -83,7 +86,7 @@ function ThinkRow({ text, running, t }: { text: string; running: boolean; t: Ass
|
||||
}
|
||||
|
||||
export const AssistantMarkdown = memo(function AssistantMarkdown({
|
||||
blocks, streaming, interrupted, time, runMs, ttftMs, tokensPerSecond, seq, onFork, forkUnavailable, t,
|
||||
blocks, streaming, interrupted, time, runMs, ttftMs, tokensPerSecond, seq, onFork, forkUnavailable, turnTail, t,
|
||||
}: AssistantMarkdownProps) {
|
||||
// Stable per locale revision (t identity changes on switch): a fresh object
|
||||
// per render would rebuild MarkdownText's component table every chunk.
|
||||
@@ -121,6 +124,7 @@ export const AssistantMarkdown = memo(function AssistantMarkdown({
|
||||
})}
|
||||
{interrupted && <span className={css.stopped}>{t('message.stopped')}</span>}
|
||||
</div>
|
||||
{showActions && turnTail?.renderSlotChain('conversation.chat.turnTail', turnTail.owner)}
|
||||
{showActions && (
|
||||
<MessageIconActions
|
||||
text={copyText(blocks)}
|
||||
|
||||
@@ -335,7 +335,7 @@ function StreamingTail({ useSession, t }: {
|
||||
* render through the declared keyed hole's renderSlot share).
|
||||
*/
|
||||
export function ChatView({
|
||||
useSession, useSessions, useStore, renderSlot, sessionId, openFile, loadOlder, inspectCall, chatScroll, forkAt, t,
|
||||
useSession, useSessions, useStore, renderSlot, renderSlotChain, sessionId, openFile, loadOlder, inspectCall, chatScroll, forkAt, t,
|
||||
}: ChatViewSlotProps) {
|
||||
const nodes = useSession(s => s.nodes)
|
||||
const turnTimings = useSession(s => s.turnTimings)
|
||||
@@ -600,6 +600,9 @@ export function ChatView({
|
||||
seq={node.seq}
|
||||
onFork={forkAt}
|
||||
forkUnavailable={!branchSeqs.has(node.seq)}
|
||||
turnTail={actionSeqs.has(node.seq)
|
||||
? { renderSlotChain, owner: { nodes, seq: node.seq, openFile } }
|
||||
: undefined}
|
||||
t={t}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
color: var(--dsw-alias-label-tertiary);
|
||||
}
|
||||
|
||||
/* File-tool path: same geometry as .summary; hover underline + pointer. */
|
||||
/* File-tool path: same geometry as .summary, with a persistent link affordance. */
|
||||
.fileLink {
|
||||
flex: 1 1 auto;
|
||||
min-width: 0;
|
||||
@@ -118,12 +118,16 @@
|
||||
text-align: left;
|
||||
font-size: 14px;
|
||||
line-height: 24px;
|
||||
color: var(--dsw-alias-label-tertiary);
|
||||
color: var(--dsw-alias-label-secondary);
|
||||
text-decoration: underline;
|
||||
text-decoration-color: var(--dsw-alias-label-quaternary);
|
||||
text-underline-offset: 3px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.fileLink:hover {
|
||||
text-decoration: underline;
|
||||
color: var(--dsw-alias-label-primary);
|
||||
text-decoration-color: currentColor;
|
||||
}
|
||||
|
||||
/* Error row's collapsed summary: the failure's first line in the error color. */
|
||||
|
||||
@@ -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, SessionId, ToolCallBlock, WorkspaceId } from '@deepseek-ai/dsh-client-runtime/client'
|
||||
import type { CommandNode, ConversationNode, 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'
|
||||
@@ -46,6 +46,14 @@ declare module '@deepseek-ai/dsh-client-ui-slots' {
|
||||
* registration, and a domain upgrades by registering one row component.
|
||||
*/
|
||||
'conversation.chat.commandview': { kind: 'keyed'; scope: 'session'; owner: CommandRowOwnerProps }
|
||||
/**
|
||||
* The chat view's turn-tail chain: rendered between a closing assistant
|
||||
* message's body and its IconActions footer, once per turn (the render
|
||||
* site elects the closing seq). Entries derive a match from the owner
|
||||
* currency before mounting, so presentation components never mount only
|
||||
* to return null; an all-declined chain renders nothing.
|
||||
*/
|
||||
'conversation.chat.turnTail': { kind: 'chain'; scope: 'session'; owner: TurnTailOwnerProps }
|
||||
/**
|
||||
* The composer takeover chain: entries are selector-routed replacements
|
||||
* of the default InputBar. Declared by this package's 'conversation'
|
||||
@@ -150,6 +158,24 @@ export interface ConvViewOwnerProps {
|
||||
onInspectDone?: () => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Owner currency of the chat view's turn-tail hole: the finalized snapshot
|
||||
* and the closing assistant's anchor. Registrants derive their own facts
|
||||
* from the nodes (the owner never pre-chews a feature's vocabulary), and
|
||||
* open files through the same opener the tool rows use.
|
||||
*/
|
||||
export interface TurnTailOwnerProps {
|
||||
/** Finalized snapshot nodes in surface order. */
|
||||
nodes: readonly ConversationNode[]
|
||||
/** The closing assistant's seq — the anchor the tail renders under. */
|
||||
seq: number
|
||||
/**
|
||||
* Open a filesystem path through the Host (tool-row semantics; the chat
|
||||
* view resolves relative paths against the session cwd).
|
||||
*/
|
||||
openFile: (path: string) => void
|
||||
}
|
||||
|
||||
/**
|
||||
* Owner share of a per-view toolview slot: the call material the rendering
|
||||
* view supplies per row. Uniform across views — the trajectory/waterfall
|
||||
@@ -480,7 +506,7 @@ export interface ChatViewInjected {
|
||||
|
||||
/** Full chat-view component props: runtime & the declared toolview/commandview holes' render share & store & injected & locale seat. */
|
||||
export type ChatViewSlotProps =
|
||||
PropsRuntime<'conversation.view'> & PropsRenderSlots<'conversation.chat.toolview' | 'conversation.chat.commandview'>
|
||||
PropsRuntime<'conversation.view'> & PropsRenderSlots<'conversation.chat.toolview' | 'conversation.chat.commandview' | 'conversation.chat.turnTail'>
|
||||
& PropsStore<ChatStore> & ChatViewInjected & PropsLocale<'conversation'>
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,7 +17,7 @@ export type {
|
||||
ComposerChainProps, ConversationInjected,
|
||||
ConversationSessionHeaderInjected, ConversationSessionInjected, ConversationSlotProps,
|
||||
ConvViewOwnerProps, ConvViewProps, DetailsInjected, DetailsSlotProps,
|
||||
EmptyWorkspaceOwnerProps, ToolRowOwnerProps, ToolRowProps,
|
||||
EmptyWorkspaceOwnerProps, ToolRowOwnerProps, ToolRowProps, TurnTailOwnerProps,
|
||||
} from './contract/slots.ts'
|
||||
// Export discipline: packages/client/AGENTS.md.
|
||||
|
||||
|
||||
@@ -24,12 +24,12 @@
|
||||
}
|
||||
|
||||
/* figma 34:10411: fish + title, gap 10, centered; 26/32 wt500. The preview
|
||||
badge is a product addition outside that source and aligns to the title. */
|
||||
badge is a product addition outside that source: a mono superscript pill
|
||||
riding the title's top-right. */
|
||||
.headline {
|
||||
display: grid;
|
||||
grid-template-columns: 34px auto;
|
||||
grid-template-columns: 34px auto auto;
|
||||
column-gap: 10px;
|
||||
row-gap: 4px;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-size: 26px;
|
||||
@@ -44,13 +44,17 @@
|
||||
}
|
||||
|
||||
.previewBadge {
|
||||
grid-row: 2;
|
||||
grid-column: 2;
|
||||
justify-self: start;
|
||||
padding: 0 4px;
|
||||
border-radius: 4px;
|
||||
grid-row: 1;
|
||||
grid-column: 3;
|
||||
align-self: start;
|
||||
margin-top: 2px;
|
||||
margin-left: -3px;
|
||||
padding: 1px 7px 0;
|
||||
border: 1px solid var(--dsw-alias-interactive-bg-hover);
|
||||
border-radius: 24px;
|
||||
background: var(--dsw-alias-state-business-tertiary);
|
||||
color: var(--dsw-alias-label-primary);
|
||||
color: var(--dsw-alias-label-primary-bluish);
|
||||
font-family: var(--ds-font-family-code);
|
||||
font-size: 12px;
|
||||
line-height: 18px;
|
||||
font-weight: 500;
|
||||
|
||||
Reference in New Issue
Block a user