@morlay/ui-conversation-message-actions 0.0.11 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -6
- package/dist/client.js +831 -0
- package/{lib → dist}/index.d.mts +0 -58
- package/dist/index.d.mts.map +1 -0
- package/{lib → dist}/index.mjs +2 -80
- package/dist/index.mjs.map +1 -0
- package/dist/invariant.d.mts +8 -0
- package/dist/invariant.d.mts.map +1 -0
- package/dist/invariant.mjs +10 -0
- package/dist/invariant.mjs.map +1 -0
- package/package.json +35 -26
- package/src/client/chat-node/MessageEditDialog.module.css +24 -0
- package/src/client/chat-node/MessageEditDialog.tsx +71 -0
- package/src/client/chat-node/MessageIconActions.module.css +86 -0
- package/src/client/chat-node/MessageIconActions.tsx +189 -0
- package/src/client/chat-node/MessageItem.module.css +290 -0
- package/src/client/chat-node/MessageItem.tsx +198 -0
- package/src/client/chat-node/message-chrome.ts +61 -0
- package/src/client/chat-node/register.ts +33 -0
- package/src/client/chat-node/use-calendar-day.ts +23 -0
- package/src/client/controller.ts +327 -0
- package/src/client/css-modules.d.ts +4 -0
- package/src/client/import-action.tsx +74 -0
- package/src/client/index.ts +50 -0
- package/src/index.ts +936 -0
- package/src/invariant.ts +13 -0
- package/src/shared.ts +167 -0
- package/src/types.ts +73 -0
- package/lib/client.js +0 -2243
- package/lib/client.js.map +0 -1
- package/lib/index.d.mts.map +0 -1
- package/lib/index.mjs.map +0 -1
- package/lib/invariant.d.mts +0 -15
- package/lib/invariant.d.mts.map +0 -1
- package/lib/invariant.mjs +0 -22
- package/lib/invariant.mjs.map +0 -1
package/lib/client.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","names":["createSnapshotStore","useRef","useCallback","useState","useRef","css","a11yCss","DisclosureRow","IconThinkOutline14","memo","useMemo","MarkdownText","Fragment","JsonBlock","css","memo","useMemo","memo","useState","css","IconApiOutline14","IconChevronDownOutline14","IconChevronRightOutline14","MarkdownText","StateDot","IconApiOutline14","useState","css","a11yCss","DisclosureRow","memo","useMemo","css","css","JsonBlock","unreachable","useState","DisclosureRow","css","IconBrowseOutline16","useState","useId","useState","useRef","useCallback","writeClipboard","css","Tooltip","IconCheckOutline16","IconCopyOutline16","IconEditOutline16","IconRefreshOutline16","IconBranchOutline16","useState","useRef","Modal","css","Button","useMemo","useState","css","StateDot","MessageText","JsonBlock","memo","Modal","Button","memo","css","useState","useCallback","Button","IconRefreshOutline16"],"sources":["../src/shared.ts","../src/client/controller.ts","../src/client/chat-node/use-throttled-visual-update.ts","../src/client/chat-node/ReasoningRow.tsx","../src/client/chat-node/AssistantMarkdown.tsx","../src/client/chat-node/AssistantNodeView.tsx","../src/client/chat-node/CompactionItem.tsx","../src/client/chat-node/GenericCommandCard.tsx","../src/client/chat-node/CompactionCommandCard.tsx","../src/client/chat-node/CommandNodeView.tsx","../src/client/chat-node/ContextBody.tsx","../src/client/chat-node/ContextInjectionRow.tsx","../src/client/chat-node/message-chrome.ts","../src/client/chat-node/use-calendar-day.ts","../src/client/chat-node/MessageIconActions.tsx","../src/client/chat-node/MessageEditDialog.tsx","../src/client/chat-node/MessageItem.tsx","../src/client/chat-node/turn-assistant.ts","../src/client/chat-node/TurnTailNodeView.tsx","../src/client/chat-node/register.ts","../src/client/cleanse-session-action.tsx","../src/client/index.ts"],"sourcesContent":["/**\n * Host 与 client 共享的类型与常量:HTTP 路由、操作判别联合、Timeline 响应。\n *\n * @module @morlay/ui-conversation-message-actions/shared\n */\n\nimport type { SessionId } from \"@deepseek-ai/dsh-session\";\nimport type { BranchTimeline, CascadePolicy } from \"@morlay/session-branch\";\nimport type { VersionOperation } from \"@morlay/session-branch\";\n\n/** 同源 HTTP 端点(host 注册、client fetch)。 */\nexport const SESSION_EDITOR_PATH = \"/session-editor\";\n\nexport type { VersionOperation } from \"@morlay/session-branch\";\n\n/** 编辑一个已落定文本块并从其轮次边界分支。 */\nexport interface EditOperation {\n action: \"edit\";\n sessionId: SessionId;\n eventSeq: number;\n blockIndex: number;\n text: string;\n cascade: CascadePolicy;\n}\n\n/** 重生成最后一条已落定助手回复。 */\nexport interface RerollOperation {\n action: \"reroll\";\n sessionId: SessionId;\n}\n\n/** 重试任意历史回合。 */\nexport interface RetryOperation {\n action: \"retry\";\n sessionId: SessionId;\n turn: number;\n cascade: CascadePolicy;\n}\n\n/** 截断式回退:原会话回退到闭合边界。 */\nexport interface RewindOperation {\n action: \"rewind\";\n sessionId: SessionId;\n toBoundary: number;\n}\n\n/** 派生式分支:从闭合边界派生新会话。 */\nexport interface ForkOperation {\n action: \"fork\";\n sessionId: SessionId;\n atSeq?: number;\n childSessionId?: SessionId;\n}\n\n/** 清洗一个会话的 surface/provenance 坐标为稠密空间(修复历史加载失败)。 */\nexport interface CleanseOperation {\n action: \"cleanse\";\n sessionId: SessionId;\n}\n\n/** HTTP 接受的判别联合。 */\nexport type SessionEditorOperation =\n | EditOperation\n | RerollOperation\n | RetryOperation\n | RewindOperation\n | ForkOperation\n | CleanseOperation;\n\n/** 操作响应(分支式返回新版本 id;rewind 返回原 id)。 */\nexport interface SessionEditorOperationResult {\n sessionId: SessionId;\n queuedTurns: number;\n /** 操作后会话是否仍有 live owner(客户端据此决定是否重载页面)。 */\n live?: boolean;\n /** cleanse 操作实际重写的事件数。 */\n changed?: number;\n}\n\n/** 可编辑文本块(编辑面枚举)。 */\nexport interface EditableMessageBlock {\n key: string;\n turn: number;\n eventSeq: number;\n blockIndex: number;\n kind: \"user\" | \"assistant.reasoning\" | \"assistant.response\";\n text: string;\n time: number;\n}\n\n/** 可重试回合(重试面枚举)。 */\nexport interface RetryableTurn {\n turn: number;\n userEventSeq: number;\n preview: string;\n time: number;\n}\n\n/** 版本摘要(Timeline 节点投影,值级)。 */\nexport interface VersionSummary {\n sessionId: string;\n parentSessionId?: string;\n effectId?: string;\n inverseSessionId?: string;\n createdAt: number;\n depth: number;\n current: boolean;\n onCurrentEffectPath: boolean;\n operation?: VersionOperation;\n cascade?: CascadePolicy;\n targetTurn?: number;\n blockKind?: EditableMessageBlock[\"kind\"];\n before?: string;\n after?: string;\n}\n\n/** GET /session-editor 的完整投影(Timeline + 编辑/重试面)。 */\nexport interface SessionEditorTimeline {\n sessionId: string;\n messages: EditableMessageBlock[];\n retryableTurns: RetryableTurn[];\n versions: VersionSummary[];\n /** 原子逆链(从当前版本向外,应用顺序)。 */\n undoStack: string[];\n /** 可直接重施加的子版本。 */\n redoSessionIds: string[];\n}\n\n/** 把 {@link BranchTimeline} 投影成 client 用的 {@link SessionEditorTimeline}。 */\nexport function toTimelinePayload(\n sessionId: SessionId,\n timeline: BranchTimeline,\n messages: EditableMessageBlock[],\n retryableTurns: RetryableTurn[],\n): SessionEditorTimeline {\n const currentPath = new Set<string>();\n for (const node of timeline.nodes) currentPath.add(String(node.sessionId));\n const versions: VersionSummary[] = timeline.nodes.map((node) => ({\n sessionId: String(node.sessionId),\n ...(node.parentSessionId === undefined\n ? {}\n : { parentSessionId: String(node.parentSessionId) }),\n ...(node.effect === undefined\n ? {}\n : {\n effectId: node.effect.id,\n inverseSessionId: String(node.inverseSessionId),\n operation: node.effect.operation,\n cascade: node.effect.cascade,\n targetTurn: node.effect.targetTurn,\n ...(node.effect.blockKind === undefined ? {} : { blockKind: node.effect.blockKind }),\n ...(node.effect.before === undefined ? {} : { before: node.effect.before }),\n ...(node.effect.after === undefined ? {} : { after: node.effect.after }),\n }),\n createdAt: node.createdAt,\n depth: depthOf(timeline, node.sessionId),\n current: String(node.sessionId) === String(sessionId),\n onCurrentEffectPath: currentPath.has(String(node.sessionId)),\n }));\n const versionsById = new Map(versions.map((version) => [version.sessionId, version]));\n const undoStack: string[] = [];\n let cursor = versionsById.get(String(sessionId));\n while (cursor?.inverseSessionId !== undefined) {\n if (undoStack.includes(cursor.inverseSessionId)) break;\n undoStack.push(cursor.inverseSessionId);\n cursor = versionsById.get(cursor.inverseSessionId);\n }\n const redoSessionIds = versions\n .filter((version) => version.inverseSessionId === String(sessionId))\n .map((version) => version.sessionId);\n return {\n sessionId: String(sessionId),\n messages,\n retryableTurns,\n versions,\n undoStack,\n redoSessionIds,\n };\n}\n\n/** 计算节点到根的深度。 */\nfunction depthOf(\n timeline: BranchTimeline,\n sessionId: import(\"@deepseek-ai/dsh-session\").SessionId,\n): number {\n const byId = new Map(timeline.nodes.map((node) => [String(node.sessionId), node]));\n let depth = 0;\n let cursor = byId.get(String(sessionId));\n const seen = new Set<string>();\n while (cursor?.parentSessionId !== undefined && !seen.has(String(cursor.sessionId))) {\n seen.add(String(cursor.sessionId));\n depth += 1;\n cursor = byId.get(String(cursor.parentSessionId));\n }\n return depth;\n}\n","/**\n * Browser controller for one session's Timeline projection and branch mutations.\n * 精简版:HTTP 拉取 timeline + 执行操作 + 会话导航(openWhenListed)。\n */\n\nimport type {\n ClientContext,\n ConversationSnapshot,\n ISessions,\n ObservableSnapshot,\n SessionFace,\n SessionId,\n SnapshotStore,\n} from \"@deepseek-ai/dsh-client-runtime/client\";\nimport { createSnapshotStore } from \"@deepseek-ai/dsh-client-runtime/client\";\nimport {\n SESSION_EDITOR_PATH,\n type EditableMessageBlock,\n type SessionEditorOperation,\n type SessionEditorOperationResult,\n type SessionEditorTimeline,\n type VersionOperation,\n} from \"../shared.ts\";\n\nexport interface SessionEditorState {\n status: \"idle\" | \"loading\" | \"ready\" | \"error\";\n error: string | null;\n pending: VersionOperation | \"cleanse\" | null;\n timeline: SessionEditorTimeline | null;\n /** 会话历史加载失败(openState === \"error\")——据此显示「清洗会话」入口。 */\n sessionOpenError: boolean;\n}\n\n/** 业务 face;渲染层绑定到保留的 source compartment。 */\nexport interface SessionEditorFace {\n hooks: { sessionEditor: ObservableSnapshot<SessionEditorState> };\n acquire(): () => void;\n load(): void;\n edit(\n message: EditableMessageBlock,\n text: string,\n cascade: \"truncate\" | \"preserve\",\n ): Promise<boolean>;\n retry(turn: number, cascade: \"truncate\" | \"preserve\"): Promise<boolean>;\n reroll(): Promise<boolean>;\n rewind(toBoundary: number): Promise<boolean>;\n /** 清洗当前会话的 provenance 坐标为稠密空间(修复历史加载失败)。 */\n cleanse(): Promise<boolean>;\n openVersion(sessionId: string): Promise<void>;\n}\n\nfunction messageOf(error: unknown): string {\n return error instanceof Error ? error.message : String(error);\n}\n\nfunction conversationRevision(snapshot: ConversationSnapshot): string {\n const turnEnds = [...snapshot.turnEnds.entries()]\n .map(([turn, seq]) => `${String(turn)}:${String(seq)}`)\n .join(\",\");\n return [snapshot.openState, snapshot.removed, snapshot.hasMore, turnEnds].join(\"|\");\n}\n\n/** 一个会话共享一个稳定 controller(header + timeline 两个入口复用)。 */\nexport class SessionEditorController {\n readonly store: SnapshotStore<SessionEditorState> = createSnapshotStore<SessionEditorState>({\n status: \"idle\",\n error: null,\n pending: null,\n timeline: null,\n sessionOpenError: false,\n });\n\n readonly face: SessionEditorFace;\n private readonly ctx: ClientContext;\n private readonly sessions: ISessions;\n private sessionSource: SessionFace | undefined;\n private sessionSourceDispose: (() => void) | undefined;\n private sessionRevision: string | undefined;\n private disposed = false;\n private users = 0;\n private readonly navigationWaits = new Set<() => void>();\n\n constructor(\n ctx: ClientContext,\n private readonly sessionId: SessionId,\n ) {\n this.ctx = ctx;\n this.sessions = ctx.get(\"sessions\") as unknown as ISessions;\n this.face = {\n hooks: { sessionEditor: this.store },\n acquire: () => {\n this.users += 1;\n if (this.users === 1 && this.disposed) this.revive();\n return () => this.release();\n },\n load: () => {\n void this.load();\n },\n edit: (message, text, cascade) =>\n this.mutate({\n action: \"edit\",\n sessionId: this.sessionId,\n eventSeq: message.eventSeq,\n blockIndex: message.blockIndex,\n text,\n cascade,\n }),\n retry: (turn, cascade) =>\n this.mutate({ action: \"retry\", sessionId: this.sessionId, turn, cascade }),\n reroll: () => this.mutate({ action: \"reroll\", sessionId: this.sessionId }),\n rewind: (toBoundary) =>\n this.mutate({ action: \"rewind\", sessionId: this.sessionId, toBoundary }),\n cleanse: () => this.mutate({ action: \"cleanse\", sessionId: this.sessionId }),\n openVersion: (sessionId) => this.openWhenListed(sessionId as SessionId),\n };\n this.observe();\n }\n\n private observe(): void {\n this.sessionSource = undefined;\n this.sessionSourceDispose?.();\n this.bindSessionSource();\n this.sessions.list.subscribe(() => this.invalidate());\n }\n\n private bindSessionSource(): void {\n const source = this.sessions.binding(this.sessionId)?.session;\n if (source === this.sessionSource) return;\n this.sessionSourceDispose?.();\n this.sessionSource = source;\n this.sessionRevision =\n source === undefined ? undefined : conversationRevision(source.getSnapshot());\n // 历史加载失败标记:会话 snapshot 的 openState === \"error\" 时显示清洗入口。\n this.store.update((state) => {\n state.sessionOpenError = source?.getSnapshot().openState === \"error\";\n });\n this.sessionSourceDispose = source?.subscribe(() => {\n this.store.update((state) => {\n state.sessionOpenError = source.getSnapshot().openState === \"error\";\n });\n this.invalidate();\n });\n }\n\n private invalidate(): void {\n if (this.disposed || this.store.getSnapshot().status === \"idle\") return;\n // 会话状态变化 → 刷新投影(debounce 由调用方按需)。\n void this.load();\n }\n\n private release(): void {\n this.users -= 1;\n if (this.users <= 0) this.dispose();\n }\n\n private dispose(): void {\n if (this.disposed) return;\n this.disposed = true;\n this.sessionSourceDispose?.();\n this.sessionSourceDispose = undefined;\n this.sessionSource = undefined;\n this.sessionRevision = undefined;\n }\n\n private revive(): void {\n this.disposed = false;\n this.observe();\n void this.load();\n }\n\n async load(): Promise<void> {\n if (this.disposed) return;\n this.store.update((state) => {\n state.status = \"loading\";\n state.error = null;\n });\n try {\n const response = await fetch(\n `${SESSION_EDITOR_PATH}?sessionId=${encodeURIComponent(this.sessionId)}`,\n {\n method: \"GET\",\n headers: { accept: \"application/json\" },\n cache: \"no-store\",\n },\n );\n const value = (await response.json()) as unknown;\n if (this.disposed) return;\n if (response.ok) {\n this.store.update((state) => {\n state.status = \"ready\";\n state.error = null;\n state.timeline = value as SessionEditorTimeline;\n });\n } else {\n const error = (value as { error?: unknown })[\"error\"];\n this.store.update((state) => {\n state.status = \"error\";\n state.error =\n typeof error === \"string\" ? error : `请求失败:HTTP ${String(response.status)}`;\n });\n }\n } catch (error) {\n if (this.disposed) return;\n this.store.update((state) => {\n state.status = \"error\";\n state.error = messageOf(error);\n });\n }\n }\n\n private async mutate(operation: SessionEditorOperation): Promise<boolean> {\n // 只拦截并发操作;不要求 status === \"ready\"——编辑/重试的数据(eventSeq/\n // blockIndex/turn)来自客户端 conversation 节点,与 timeline 加载无关,\n // status 停留在 idle(无 HeaderActions 触发 load)时也必须能发起请求。\n const current = this.store.getSnapshot();\n if (current.pending !== null) return false;\n this.store.update((state) => {\n state.pending = operation.action;\n state.error = null;\n });\n try {\n const response = await fetch(SESSION_EDITOR_PATH, {\n method: \"POST\",\n headers: { accept: \"application/json\", \"content-type\": \"application/json\" },\n body: JSON.stringify(operation),\n });\n const value = (await response.json()) as unknown;\n if (this.disposed) return true;\n if (!response.ok) {\n const error = (value as { error?: unknown })[\"error\"];\n throw new Error(\n typeof error === \"string\" ? error : `请求失败:HTTP ${String(response.status)}`,\n );\n }\n this.store.update((state) => {\n state.pending = null;\n });\n const result = value as SessionEditorOperationResult;\n // edit / retry / reroll 就地编辑(不改变 session id),仅 fork 产生新 id\n // 时才需要等列表发布并打开新版本。\n if (String(result.sessionId) !== String(this.sessionId)) {\n await this.openWhenListed(result.sessionId as SessionId);\n return true;\n }\n // 就地编辑:rewind 会**删除**事件,客户端 conversation 事件流(append-only\n // 发布)无法表达删除——seq 回退只做增量,被剪掉的旧节点会残留。\n // 优先\"会话级刷新\"(resync:重置窗口并重新拉取历史,不整页重载);\n // resync 不可用时回退整页重载。\n const face = this.sessions.binding(this.sessionId)?.session;\n const resync = (face as unknown as { resync?: () => Promise<void> }).resync;\n if (resync !== undefined) {\n try {\n await resync.call(face);\n void this.load();\n return true;\n } catch {\n // fall through to full reload\n }\n }\n location.reload();\n return true;\n } catch (error) {\n if (this.disposed) return false;\n this.store.update((state) => {\n state.pending = null;\n state.error = messageOf(error);\n });\n return false;\n }\n }\n\n /** 会话列表发布是导航的反应式依赖:等新版本出现在列表后再打开。 */\n private openWhenListed(sessionId: SessionId): Promise<void> {\n if (this.sessions.list.getSnapshot().byId[sessionId] !== undefined) {\n this.sessions.open(sessionId);\n return Promise.resolve();\n }\n return new Promise((resolve) => {\n let settled = false;\n let dispose = (): void => {};\n const finish = (open: boolean): void => {\n if (settled) return;\n settled = true;\n dispose();\n this.navigationWaits.delete(cancel);\n if (open) this.sessions.open(sessionId);\n resolve();\n };\n const cancel = (): void => {\n finish(false);\n };\n this.navigationWaits.add(cancel);\n dispose = this.sessions.list.subscribe(() => {\n if (this.sessions.list.getSnapshot().byId[sessionId] === undefined) return;\n finish(true);\n });\n if (this.sessions.list.getSnapshot().byId[sessionId] !== undefined) finish(true);\n });\n }\n}\n","/** Frame-throttled scheduling for non-essential visual alignment. */\nimport { useCallback, useLayoutEffect, useRef } from \"react\";\n\nconst DEFAULT_INTERVAL_FRAMES = 3;\n\n/**\n * Return a stable scheduler that coalesces visual updates over a frame interval.\n * @param update - DOM alignment to run after the throttle interval.\n * @param intervalFrames - frames to wait before applying the latest alignment.\n * @returns a stable function that schedules the latest update.\n */\nexport function useThrottledVisualUpdate(\n update: () => void,\n intervalFrames = DEFAULT_INTERVAL_FRAMES,\n): () => void {\n const updateRef = useRef(update);\n updateRef.current = update;\n const pendingFrameRef = useRef<number | null>(null);\n\n useLayoutEffect(\n () => () => {\n if (pendingFrameRef.current === null) return;\n cancelAnimationFrame(pendingFrameRef.current);\n pendingFrameRef.current = null;\n },\n [],\n );\n\n return useCallback(() => {\n if (pendingFrameRef.current !== null) return;\n let remainingFrames = intervalFrames;\n const advance = (): void => {\n remainingFrames -= 1;\n if (remainingFrames > 0) {\n pendingFrameRef.current = requestAnimationFrame(advance);\n return;\n }\n pendingFrameRef.current = null;\n updateRef.current();\n };\n pendingFrameRef.current = requestAnimationFrame(advance);\n }, [intervalFrames]);\n}\n","/** Assistant reasoning disclosure, independent of Tool-call presentation. */\nimport { useEffect, useRef, useState } from \"react\";\nimport { DisclosureRow, IconThinkOutline14 } from \"@deepseek-ai/dsh-client-ui-primitives\";\nimport type { ChatViewSlotProps } from \"@deepseek-ai/dsh-client-ui-conversation/client\";\nimport { useThrottledVisualUpdate } from \"./use-throttled-visual-update.ts\";\nimport a11yCss from \"./accessibility.module.css\";\nimport css from \"./ReasoningRow.module.css\";\n\nfunction firstLine(text: string): string {\n const newline = text.indexOf(\"\\n\");\n return newline === -1 ? text : text.slice(0, newline);\n}\n\nfunction latestLine(text: string): string {\n const visible = text.trimEnd();\n const newline = visible.lastIndexOf(\"\\n\");\n return newline === -1 ? visible : visible.slice(newline + 1);\n}\n\n/**\n * Render one assistant reasoning block as the Think disclosure row.\n * @param props.text - complete or streaming reasoning text.\n * @param props.running - whether this block is the streaming tail.\n * @param props.t - conversation locale seat for the running status.\n * @returns the reasoning disclosure.\n */\nexport function ReasoningRow({\n text,\n running,\n t,\n}: {\n text: string;\n running: boolean;\n t: ChatViewSlotProps[\"t\"];\n}) {\n const [expanded, setExpanded] = useState(false);\n const summaryRef = useRef<HTMLSpanElement>(null);\n const summary = running ? latestLine(text) : firstLine(text);\n const scheduleSummaryScroll = useThrottledVisualUpdate(() => {\n const element = summaryRef.current;\n if (element === null) return;\n element.scrollLeft = running ? element.scrollWidth - element.clientWidth : 0;\n });\n useEffect(() => {\n scheduleSummaryScroll();\n }, [running, scheduleSummaryScroll, summary]);\n\n return (\n <div className={css.root} data-variant=\"think\" data-state={running ? \"running\" : \"ok\"}>\n {running && <span className={a11yCss.visuallyHidden}>{t(\"row.running\")}</span>}\n <DisclosureRow\n rowClassName={css.row}\n leadingClassName={css.leading}\n titleClassName={css.title}\n chevronClassName={css.chevron}\n icon={<IconThinkOutline14 size={14} />}\n title=\"Think\"\n open={expanded}\n expandable\n expandOnRowClick\n onToggle={() => {\n setExpanded((value) => !value);\n }}\n collapsedContent={\n <>\n <span className={css.separator} aria-hidden />\n <span ref={summaryRef} className={css.summary} data-follow-end={running || undefined}>\n {summary}\n </span>\n </>\n }\n >\n <div className={css.thinkBody}>{text}</div>\n </DisclosureRow>\n </div>\n );\n}\n","// AssistantMarkdown: renders assistant blocks in order — markdown text body,\n// reasoning as the figma Think summary row (expand = indented gray text),\n// other-block JSON fallback. Tool-call heads are NOT rendered here: the chat\n// view groups them into tool rows through its keyed toolview slot (figma\n// step-summary flow). Shared by finalized nodes and the streaming partial;\n// the turn-level loading dots live in the chat view's tail, not here.\n// Finalized content (text) nodes append IconActions once their turn ends\n// (`time` is omitted for mid-turn narration and while the turn still runs);\n// their branch action is enabled only when the node is also the completed\n// turn's transcript tail. Think / tool-head-only nodes stay chrome-free.\n\nimport { Fragment, memo, useMemo } from \"react\";\nimport type { ReactNode } from \"react\";\nimport type { AssistantBlock } from \"@deepseek-ai/dsh-client-runtime/client\";\nimport { JsonBlock, MarkdownText } from \"@deepseek-ai/dsh-client-ui-primitives\";\nimport type { MarkdownFileMentions } from \"@deepseek-ai/dsh-client-ui-primitives\";\nimport type {\n ChatViewSlotProps,\n RenderMessageImages,\n} from \"@deepseek-ai/dsh-client-ui-conversation/client\";\nimport { ReasoningRow } from \"./ReasoningRow.tsx\";\nimport css from \"./AssistantMarkdown.module.css\";\n\nexport interface AssistantMarkdownProps {\n blocks: readonly AssistantBlock[];\n streaming: boolean;\n /** Frozen partial of an aborted turn: rendered with a stopped marker. */\n interrupted?: boolean | undefined;\n /** Render a consecutive image group through the attachment slot. */\n renderMessageImages: RenderMessageImages;\n /** Resolved prose file mentions for this Assistant's closing turn. */\n mentions?: MarkdownFileMentions | undefined;\n /** The owning view's locale seat, passed down as a plain prop. */\n t: ChatViewSlotProps[\"t\"];\n}\n\n/** Reasoning block as the Think variant summary row (figma 39:28304). */\nexport const AssistantMarkdown = memo(function AssistantMarkdown({\n blocks,\n streaming,\n interrupted,\n renderMessageImages,\n mentions,\n t,\n}: AssistantMarkdownProps) {\n // Stable per locale revision (t identity changes on switch): a fresh object\n // per render would rebuild MarkdownText's component table every chunk.\n const codeLabels = useMemo(\n () => ({ copyLabel: t(\"copy\" as never), copiedLabel: t(\"copied\" as never) }),\n [t],\n );\n const last = blocks.length - 1;\n // Tool-call heads render as tool rows in the chat view's grouping pass, so\n // a node that is only those heads (or empty) would paint an empty root\n // between tool groups — skip the shell unless something visible remains.\n const hasVisible =\n streaming || interrupted === true || blocks.some((block) => block.kind !== \"tool-call\");\n if (!hasVisible) return null;\n const rendered: ReactNode[] = [];\n for (let i = 0; i < blocks.length; i++) {\n const block = blocks[i];\n if (block === undefined) continue;\n switch (block.kind) {\n case \"text\":\n rendered.push(\n <MarkdownText\n key={i}\n text={block.text}\n streaming={streaming}\n codeLabels={codeLabels}\n fileMentions={mentions}\n />,\n );\n break;\n case \"reasoning\":\n rendered.push(\n <ReasoningRow key={i} text={block.text} running={streaming && i === last} t={t} />,\n );\n break;\n case \"image\": {\n // Consecutive image blocks share one gallery so several images tile\n // into rows instead of each opening a one-image group of its own.\n // Keyed by the group's FIRST block index: a streaming append that\n // extends the group then only grows `images` instead of remounting\n // the gallery under a shifted key.\n const start = i;\n const group = [block];\n while (i + 1 < blocks.length) {\n const next = blocks[i + 1];\n if (next === undefined || next.kind !== \"image\") break;\n group.push(next);\n i += 1;\n }\n rendered.push(\n <Fragment key={start}>\n {renderMessageImages({\n images: group.map(({ attachment }) => ({ attachment })),\n align: \"start\",\n })}\n </Fragment>,\n );\n break;\n }\n // Grouped into tool rows by ChatView; hasVisible above skips an empty shell.\n case \"tool-call\":\n break;\n default:\n rendered.push(\n <JsonBlock\n key={i}\n label={t(\"message.unknownBlock\")}\n payload={block.block}\n truncatedLabel={(total) => t(\"json.truncated\", { total })}\n />,\n );\n }\n }\n return (\n <div className={css.root} data-streaming={streaming || undefined}>\n <div className={css.body}>\n {rendered}\n {interrupted && <span className={css.stopped}>{t(\"message.stopped\")}</span>}\n </div>\n </div>\n );\n});\n","import { memo, useMemo } from \"react\";\nimport type {\n ChatNodeViewProps,\n TurnTailOwnerProps,\n} from \"@deepseek-ai/dsh-client-ui-conversation/client\";\nimport { AssistantMarkdown } from \"./AssistantMarkdown.tsx\";\n\n/** Streaming, settled, and interrupted Assistant states share one keyed renderer instance. */\nexport const AssistantNodeView = memo(function AssistantNodeView({\n node,\n useTurnData,\n openFile,\n renderMessageImages,\n fileMentions,\n t,\n}: ChatNodeViewProps<\"assistant-step\">) {\n const data = node.data;\n const turn =\n node.location.kind === \"turn\" || node.location.kind === \"step\" ? node.location.turn : undefined;\n const tail = useTurnData(\"turn-tail\");\n const owner = useMemo<TurnTailOwnerProps | undefined>(() => {\n if (turn?.status !== \"closed\" || data.finalNode === undefined) return undefined;\n if (tail?.closing?.finalNode.seq !== data.finalNode.seq) return undefined;\n return { turn, seq: data.finalNode.seq, openFile };\n }, [data.finalNode, openFile, tail, turn]);\n const mentions = useMemo(\n () => (owner === undefined ? undefined : fileMentions(owner)),\n [fileMentions, owner],\n );\n return (\n <AssistantMarkdown\n blocks={data.blocks}\n streaming={data.status === \"running\"}\n interrupted={data.status === \"interrupted\"}\n renderMessageImages={renderMessageImages}\n mentions={mentions}\n t={t}\n />\n );\n});\n","// CompactionItem: the one row a landed compaction contributes to the flow.\n// The conversation it shadowed on the model surface stays above it, so this\n// marker reports where the model stopped seeing that history — it never\n// replaces it. The framed checkpoint payload is written for the model and is\n// not rendered; the disclosure shows the summary from the checkpoint's own\n// cited `compaction/summary` event, and a window cut that left that event outside makes the row\n// non-expandable rather than empty.\n\nimport { memo, useState } from \"react\";\nimport type { CompactionSummaryNode } from \"@deepseek-ai/dsh-client-runtime/client\";\nimport {\n IconApiOutline14,\n IconChevronDownOutline14,\n IconChevronRightOutline14,\n MarkdownText,\n} from \"@deepseek-ai/dsh-client-ui-primitives\";\nimport type { ChatViewSlotProps } from \"@deepseek-ai/dsh-client-ui-conversation/client\";\nimport css from \"./MessageItem.module.css\";\n\ninterface CompactionItemProps {\n node: CompactionSummaryNode;\n /** Optional command title for a manual compaction folded into this marker. */\n title?: string;\n /** Command settlement text used when structured compaction counts are unavailable. */\n fallbackSummary?: string | null;\n /** The owning view's locale seat. */\n t: ChatViewSlotProps[\"t\"];\n}\n\n/**\n * The collapsed-by-default compaction marker.\n * @param props - the marker node off the snapshot cache.\n * @returns the marker row, with the summary disclosure when one is available.\n */\nexport const CompactionItem = memo(function CompactionItem({\n node,\n title,\n fallbackSummary,\n t,\n}: CompactionItemProps) {\n const [expanded, setExpanded] = useState(false);\n const expandable = node.summary !== null;\n const open = expandable && expanded;\n const summary =\n node.shadowedItemCount !== null && node.shadowedTokenCount !== null\n ? t(\"message.compaction.completed\", {\n items: node.shadowedItemCount,\n tokens: node.shadowedTokenCount,\n })\n : (fallbackSummary ??\n (expandable ? t(\"message.compaction.expand\") : t(\"message.compaction.unavailable\")));\n return (\n <div className={css.compactionRow}>\n <button\n type=\"button\"\n className={css.compactionButton}\n disabled={!expandable}\n aria-expanded={expandable ? open : undefined}\n onClick={() => {\n setExpanded((value) => !value);\n }}\n >\n <span className={css.compactionLeading} aria-hidden>\n <span className={css.compactionContextIcon} data-compaction-icon=\"context\">\n <IconApiOutline14 />\n </span>\n <span\n className={css.compactionDisclosureIcon}\n data-compaction-disclosure={open ? \"expanded\" : \"collapsed\"}\n >\n {open ? <IconChevronDownOutline14 /> : <IconChevronRightOutline14 />}\n </span>\n </span>\n <span className={css.compactionTitle}>{title ?? t(\"message.compaction\")}</span>\n <span className={css.compactionSep} aria-hidden />\n <span className={css.compactionSummary}>{summary}</span>\n </button>\n {open && node.summary !== null && (\n <div className={css.compactionBody}>\n <MarkdownText text={node.summary} />\n </div>\n )}\n </div>\n );\n});\n","// GenericCommandCard: the default command row — a stripped-down\n// GenericToolCard rendering the command name and its settlement text.\n// Supplied by the chat view as the keyed commandview slot's render-site\n// fallback (an unregistered command name lands here); registrants may compose\n// it as a base, feeding the same owner payload through.\n\nimport { useState, type ReactNode } from \"react\";\nimport type {\n ChatViewSlotProps,\n CommandRowOwnerProps,\n} from \"@deepseek-ai/dsh-client-ui-conversation/client\";\nimport { DisclosureRow, IconApiOutline14, StateDot } from \"@deepseek-ai/dsh-client-ui-primitives\";\nimport a11yCss from \"./accessibility.module.css\";\nimport css from \"./GenericCommandCard.module.css\";\n\ntype CommandRowState = \"running\" | \"ok\" | \"error\";\n\n/** Node state → row state semantic (running while unsettled; outcome kind after). */\nfunction stateOf(outcome: CommandRowOwnerProps[\"node\"][\"outcome\"]): CommandRowState {\n if (outcome === null) return \"running\";\n return outcome.kind === \"error\" ? \"error\" : \"ok\";\n}\n\nfunction leadingFor(state: CommandRowState): ReactNode {\n return state === \"error\" ? <StateDot state=\"error\" /> : <IconApiOutline14 size={14} />;\n}\n\n/** Card props: the owner payload plus the render site's locale seat (plain prop). */\nexport interface GenericCommandCardProps extends CommandRowOwnerProps {\n t: ChatViewSlotProps[\"t\"];\n /** Command-specific running copy; absent uses the generic command label. */\n runningSummary?: string | undefined;\n}\n\nexport function GenericCommandCard({ node, t, runningSummary }: GenericCommandCardProps) {\n const [expanded, setExpanded] = useState(false);\n const text = node.outcome?.text;\n const summary =\n node.outcome === null\n ? (runningSummary ?? t(\"command.running\"))\n : (text ?? (node.outcome.kind === \"error\" ? t(\"command.failed\") : t(\"command.done\")));\n // Title is the bare command name: the row already reads `name · outcome`,\n // and the dispatched line's own `/` and arguments only restate what the\n // settlement text says (`permission · preset workspace-write`). A\n // cross-window node whose run page fell out of the window has no name.\n const title = node.name ?? t(\"command.title\");\n const state = stateOf(node.outcome);\n const body = text !== undefined && text.includes(\"\\n\") ? text : null;\n const open = expanded && body !== null;\n return (\n <div className={css.root} data-variant=\"others\" data-state={state}>\n {state === \"running\" && <span className={a11yCss.visuallyHidden}>{t(\"row.running\")}</span>}\n {state === \"error\" && <span className={a11yCss.visuallyHidden}>{t(\"row.failed\")}</span>}\n <DisclosureRow\n rowClassName={css.row}\n leadingClassName={css.leading}\n titleClassName={css.title}\n chevronClassName={css.chevron}\n icon={leadingFor(state)}\n title={title}\n open={open}\n expandable={body !== null}\n expandOnRowClick\n keepContentWhenOpen\n onToggle={() => {\n setExpanded((value) => !value);\n }}\n collapsedContent={\n <>\n <span className={css.separator} aria-hidden />\n <span className={css.summary} data-error={state === \"error\" || undefined}>\n {summary}\n </span>\n </>\n }\n >\n <pre className={css.body} data-error={state === \"error\" || undefined}>\n {body}\n </pre>\n </DisclosureRow>\n </div>\n );\n}\n","// CompactionCommandCard: the `/compact` command's running row and its\n// successful checkpoint disclosure. Outcomes without a checkpoint keep the\n// generic command card so no-history, cancellation, and failures retain their\n// complete handler-authored text.\n\nimport type {\n ChatViewSlotProps,\n CommandRowOwnerProps,\n} from \"@deepseek-ai/dsh-client-ui-conversation/client\";\nimport { CompactionItem } from \"./CompactionItem.tsx\";\nimport { GenericCommandCard } from \"./GenericCommandCard.tsx\";\n\ninterface CompactionCommandCardProps extends CommandRowOwnerProps {\n t: ChatViewSlotProps[\"t\"];\n}\n\n/** Render one manual compaction lifecycle without duplicating its checkpoint marker. */\nexport function CompactionCommandCard({ node, compaction, t }: CompactionCommandCardProps) {\n if (compaction !== undefined) {\n return (\n <CompactionItem\n node={compaction}\n title=\"compact\"\n fallbackSummary={node.outcome?.text ?? null}\n t={t}\n />\n );\n }\n if (node.outcome !== null) return <GenericCommandCard node={node} t={t} />;\n return <GenericCommandCard node={node} t={t} runningSummary={t(\"message.compaction.running\")} />;\n}\n","import { memo, useMemo } from \"react\";\nimport type {\n ChatNodeViewProps,\n CommandRowOwnerProps,\n} from \"@deepseek-ai/dsh-client-ui-conversation/client\";\nimport { CompactionCommandCard } from \"./CompactionCommandCard.tsx\";\nimport { GenericCommandCard } from \"./GenericCommandCard.tsx\";\nimport css from \"./ChatView.module.css\";\n\ntype CommandNodeViewProps = ChatNodeViewProps<\"command\">;\n\n/**\n * Ordinary command lifecycle renderer. 注意:shadow 注册(priority -1)无法\n * 声明 `conversation.chat.commandview` children(已被上游声明,重复声明会抛\n * 「already declared」),因此这里不消费 `renderSlot` 子 slot,直接渲染通用\n * command 卡片。\n */\nexport const CommandNodeView = memo(function CommandNodeView({ node, t }: CommandNodeViewProps) {\n const command = node.data;\n const owner = useMemo<CommandRowOwnerProps>(() => ({ node: command }), [command]);\n return (\n <div className={css.callRow}>\n <GenericCommandCard {...owner} t={t} />\n </div>\n );\n});\n\n/** One integrated `/compact` command and compaction transaction renderer. */\nexport const ManualCompactionNodeView = memo(function ManualCompactionNodeView({\n node,\n t,\n}: ChatNodeViewProps<\"manual-compaction\">) {\n const data = node.data;\n return (\n <div className={css.callRow}>\n <CompactionCommandCard\n node={data.command}\n {...(data.compaction === null ? {} : { compaction: data.compaction })}\n t={t}\n />\n </div>\n );\n});\n","// Expanded bodies for the context disclosure, one per durable context form.\n// The producer declares the form; this module only chooses a presentation for\n// it. Every form falls back to OpaqueBody, which is the documented default for\n// an absent, unknown, or malformed form — a resumed or foreign log must render\n// even when this UI version has never seen its producer.\n\nimport type { ReactNode } from \"react\";\nimport type { ContextMessageNode, KnownContextForm } from \"@deepseek-ai/dsh-client-runtime/client\";\nimport { JsonBlock } from \"@deepseek-ai/dsh-client-ui-primitives\";\nimport type { ChatViewSlotProps } from \"@deepseek-ai/dsh-client-ui-conversation/client\";\nimport css from \"./ContextBody.module.css\";\n\n/** Model-facing text stays bounded at the disclosure, not at the producer. */\nconst MAX_CHARS = 20_000;\n\n/** Rows a list body materializes before summarizing the remainder. */\nconst MAX_ENTRIES = 200;\n\ntype Translate = ChatViewSlotProps[\"t\"];\n\n/** One durable source narrowed to the readable-record shape; null for anything else. */\nfunction asRecord(value: unknown): Record<string, unknown> | null {\n return typeof value === \"object\" && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : null;\n}\n\n/** One run of the model-facing content: adjacent text, or one unknown block. */\ntype ContentRun = { text: string } | { block: unknown };\n\n/**\n * The content blocks as runs, IN THE ORDER the model received them.\n *\n * Adjacent text blocks join with no separator, matching how provider adapters\n * flatten them — inserting a line break would show the reader a line the model\n * never saw. An unknown block breaks the run and keeps its own fallback rather\n * than being hoisted past the text around it or vanishing; the block union is\n * merge-extensible, so a foreign log may interleave shapes this build does not\n * know.\n */\nfunction contentRuns(content: ContextMessageNode[\"content\"]): ContentRun[] {\n const runs: ContentRun[] = [];\n for (const block of content) {\n if (block.type !== \"text\") {\n runs.push({ block });\n continue;\n }\n const last = runs[runs.length - 1];\n if (last !== undefined && \"text\" in last) last.text += block.text;\n else runs.push({ text: block.text });\n }\n return runs;\n}\n\n/** Only the blocks this UI version does not know, for bodies that replace the text. */\nfunction unknownBlocks(content: ContextMessageNode[\"content\"]): unknown[] {\n return contentRuns(content).flatMap((run) => (\"block\" in run ? [run.block] : []));\n}\n\n/** The model-facing text, truncated to the display bound. */\nfunction boundedText(text: string, t: Translate): string {\n return text.length > MAX_CHARS\n ? `${text.slice(0, MAX_CHARS)}\\n${t(\"json.truncated\", { total: text.length })}`\n : text;\n}\n\n/**\n * One source field rendered as a value row; nested shapes stay compact JSON.\n * Bounded on its own, because source fields are as unbounded as the text: an unknown\n * producer may record an arbitrarily large string or array.\n */\nfunction fieldValue(value: unknown, t: Translate): string {\n const text =\n typeof value === \"string\"\n ? value\n : typeof value === \"number\" || typeof value === \"boolean\"\n ? String(value)\n : JSON.stringify(value);\n return boundedText(text, t);\n}\n\n/**\n * Source fields as a key/value list. `kind` is always omitted because the\n * row header already names the producer. `form` is omitted only when a\n * dedicated body rendered for it — then the presentation the reader is looking\n * at IS that value. On the opaque fallback the declaration is kept, because\n * that is the one place a form this version cannot present would otherwise\n * disappear from the UI entirely.\n */\nfunction SourceFields({\n source,\n formRendered,\n t,\n}: {\n source: unknown;\n formRendered: boolean;\n t: Translate;\n}): ReactNode {\n const record = asRecord(source);\n if (record === null) return null;\n const hidden = formRendered ? [\"kind\", \"form\"] : [\"kind\"];\n const rows = Object.entries(record).filter(([key]) => !hidden.includes(key));\n if (rows.length === 0) return null;\n return (\n <dl className={css.fields} data-context-fields>\n {rows.map(([key, value]) => (\n <div key={key} className={css.field}>\n <dt className={css.fieldKey}>{key}</dt>\n <dd className={css.fieldValue}>{fieldValue(value, t)}</dd>\n </div>\n ))}\n </dl>\n );\n}\n\n/**\n * Content blocks this UI version does not know, kept visible rather than\n * dropped: the block union is merge-extensible, so a newer or foreign log may\n * carry a shape this build has no presentation for.\n * @param props - The unrecognized blocks and the locale seat.\n * @returns One generic JSON block per unknown entry.\n */\nfunction UnknownBlocks({ blocks, t }: { blocks: readonly unknown[]; t: Translate }): ReactNode {\n return (\n <>\n {blocks.map((block, index) => (\n <JsonBlock\n key={index}\n label={t(\"message.unknownBlock\")}\n payload={block}\n truncatedLabel={(total) => t(\"json.truncated\", { total })}\n />\n ))}\n </>\n );\n}\n\n/**\n * The model-facing content of one context, shared by every form that shows it:\n * the text with its real line breaks, then any block this UI version does not\n * know, which keeps its own fallback rather than vanishing.\n * @param props - Durable content and the locale seat.\n * @returns The content blocks as the model received them.\n */\nfunction ModelFacingContent({\n content,\n t,\n}: {\n content: ContextMessageNode[\"content\"];\n t: Translate;\n}): ReactNode {\n return (\n <>\n {contentRuns(content).map((run, index) =>\n \"text\" in run ? (\n run.text !== \"\" && (\n <pre key={index} className={css.text} data-context-text>\n {boundedText(run.text, t)}\n </pre>\n )\n ) : (\n <JsonBlock\n key={index}\n label={t(\"message.unknownBlock\")}\n payload={run.block}\n truncatedLabel={(total) => t(\"json.truncated\", { total })}\n />\n ),\n )}\n </>\n );\n}\n\n/**\n * Default presentation: the model-facing text as text, with its real line\n * breaks, and the remaining source fields beneath it. This is what every form\n * this UI version does not recognize renders as.\n * @param props - Durable content, its source, and the locale seat.\n * @returns The opaque context body.\n */\nexport function OpaqueBody({\n content,\n source,\n t,\n}: {\n content: ContextMessageNode[\"content\"];\n source: unknown;\n t: Translate;\n}): ReactNode {\n return (\n <>\n <ModelFacingContent content={content} t={t} />\n <SourceFields source={source} formRendered={false} t={t} />\n </>\n );\n}\n\n/** One reconciled instruction file, as the durable source records it. */\ninterface InstructionChange {\n action: \"set\" | \"replace\" | \"remove\";\n path: string;\n digest?: string;\n}\n\n/**\n * Instruction changes read off the source, or null when the record is not a\n * usable instruction list.\n *\n * The read is all-or-nothing: silently dropping one unreadable entry would show\n * a confident, incomplete file list for a log this version cannot fully read.\n * Paths are deduplicated in first-seen order, matching how the header label is\n * derived from the same array.\n */\nfunction instructionChanges(source: unknown): InstructionChange[] | null {\n const record = asRecord(source);\n const list = record === null ? undefined : record[\"changes\"];\n if (!Array.isArray(list)) return null;\n const changes: InstructionChange[] = [];\n const seen = new Set<string>();\n for (const entry of list as readonly unknown[]) {\n const change = asRecord(entry);\n if (change === null) return null;\n const path = change[\"path\"];\n if (typeof path !== \"string\" || path === \"\") return null;\n const action = change[\"action\"];\n // The action decides which word the row shows, so an unrecognized one is\n // not a readable change — it would be presented as loaded or updated.\n if (action !== \"set\" && action !== \"replace\" && action !== \"remove\") return null;\n const digest = change[\"digest\"];\n if (seen.has(path)) continue;\n seen.add(path);\n changes.push({ action, path, ...(typeof digest === \"string\" ? { digest } : {}) });\n }\n return changes.length === 0 ? null : changes;\n}\n\n/**\n * Locale key for one reconciled file. The baseline loads a file; a later delta\n * distinguishes a newly reconciled path from a rewritten one, which `set` and\n * `replace` already separate at the producer.\n * @param action - the durable change action.\n * @param baseline - whether this context is the startup/resume baseline.\n * @returns the key naming what happened to that file.\n */\nfunction instructionAction(\n action: InstructionChange[\"action\"],\n baseline: boolean,\n):\n | \"message.context.instructions.removed\"\n | \"message.context.instructions.loaded\"\n | \"message.context.instructions.added\"\n | \"message.context.instructions.updated\" {\n if (action === \"remove\") return \"message.context.instructions.removed\";\n if (baseline) return \"message.context.instructions.loaded\";\n return action === \"set\"\n ? \"message.context.instructions.added\"\n : \"message.context.instructions.updated\";\n}\n\n/**\n * `instructions` form: the files this context reconciled, then their text.\n *\n * The text keeps its `<system-reminder>` framing verbatim — the framing is part\n * of what the model read, so hiding it would misreport the request.\n * @param props - Durable content, its source, and the locale seat.\n * @returns The instructions context body, or the opaque body when the change\n * list is unreadable.\n */\nexport function InstructionsBody({\n content,\n source,\n t,\n}: {\n content: ContextMessageNode[\"content\"];\n source: unknown;\n t: Translate;\n}): ReactNode {\n const changes = instructionChanges(source);\n if (changes === null) return <OpaqueBody content={content} source={source} t={t} />;\n const baseline = asRecord(source)?.[\"baseline\"] === true;\n return (\n <>\n <ul className={css.files} data-context-files>\n {changes.map((change) => (\n <li key={change.path} className={css.file} title={change.digest}>\n <span className={css.filePath}>{change.path}</span>\n <span className={css.fileAction}>{t(instructionAction(change.action, baseline))}</span>\n </li>\n ))}\n </ul>\n <ModelFacingContent content={content} t={t} />\n </>\n );\n}\n\n/** One catalog entry, as the durable source records it. */\ninterface CatalogEntry {\n name: string;\n description: string;\n}\n\n/**\n * Catalog entries read off the source, or null when the record is not a usable\n * catalog. All-or-nothing for the same reason as the instruction list: this body\n * replaces the model-facing text, so a partial list would hide the only complete\n * account of what the model read.\n */\nfunction catalogEntries(source: unknown): CatalogEntry[] | null {\n const record = asRecord(source);\n const list = record === null ? undefined : record[\"entries\"];\n if (!Array.isArray(list)) return null;\n const entries: CatalogEntry[] = [];\n for (const item of list as readonly unknown[]) {\n const entry = asRecord(item);\n if (entry === null) return null;\n const name = entry[\"name\"];\n const description = entry[\"description\"];\n if (typeof name !== \"string\" || name === \"\" || typeof description !== \"string\") return null;\n entries.push({ name, description });\n }\n // An empty list is a real catalog: a replacement with no entries retires\n // every earlier name. Only an unreadable shape falls back.\n return entries;\n}\n\n/**\n * `catalog` form: the published entries as a list, read from the source rather\n * than re-parsed out of the model-facing prose.\n *\n * A catalog whose source carries no usable entries falls through to the opaque\n * body, so an older or hand-edited log still shows its text.\n * @param props - Durable content, its source, and the locale seat.\n * @returns The catalog context body, or the opaque body when the entry list is\n * unreadable.\n */\nexport function CatalogBody({\n content,\n source,\n t,\n}: {\n content: ContextMessageNode[\"content\"];\n source: unknown;\n t: Translate;\n}): ReactNode {\n const entries = catalogEntries(source);\n if (entries === null) return <OpaqueBody content={content} source={source} t={t} />;\n const update = asRecord(source)?.[\"update\"] === true;\n // Entry count is unbounded (a provider may publish any number of skills), and\n // the scrollport bounds height, not node count — so the list bounds itself.\n const shown = entries.slice(0, MAX_ENTRIES);\n const rest = unknownBlocks(content);\n return (\n <>\n {update && (\n <p className={css.catalogNotice} data-context-catalog-update>\n {t(\"message.context.catalog.replaced\")}\n </p>\n )}\n <ul className={css.entries} data-context-entries>\n {shown.map((entry, index) => (\n // Index key: a hand-edited or foreign log may repeat a name, and a\n // duplicate React key would drop a row the model did see.\n <li key={index} className={css.entry}>\n <code className={css.entryName}>{entry.name}</code>\n <span className={css.entryDescription}>{entry.description}</span>\n </li>\n ))}\n </ul>\n {shown.length < entries.length && (\n <p className={css.catalogNotice} data-context-entries-truncated>\n {t(\"message.context.catalog.more\", { count: entries.length - shown.length })}\n </p>\n )}\n {/* The block union is merge-extensible: a catalog message carrying an\n unknown block still shows it rather than dropping model-visible content. */}\n <UnknownBlocks blocks={rest} t={t} />\n </>\n );\n}\n\n/** One named contribution to a runtime snapshot, as the durable source records it. */\ninterface SnapshotSection {\n name: string;\n text: string;\n}\n\n/** Snapshot sections read off the source, or null when the record is unusable. */\nfunction snapshotSections(source: unknown): SnapshotSection[] | null {\n const record = asRecord(source);\n const list = record === null ? undefined : record[\"sections\"];\n if (!Array.isArray(list)) return null;\n const sections: SnapshotSection[] = [];\n for (const item of list as readonly unknown[]) {\n const section = asRecord(item);\n if (section === null) return null;\n const name = section[\"name\"];\n const text = section[\"text\"];\n if (typeof name !== \"string\" || name === \"\" || typeof text !== \"string\") return null;\n sections.push({ name, text });\n }\n return sections.length === 0 ? null : sections;\n}\n\n/**\n * `snapshot` form: the named contributions this snapshot assembled, in order.\n *\n * The sections are the same bytes the model read, split at the boundaries the\n * producer assembled them on, so a reader sees which subsystem contributed\n * which state instead of one undifferentiated wall.\n *\n * One sentence of the model-facing text is NOT in any section: the producer's\n * framing line declaring that this snapshot supersedes earlier ones. Unlike the\n * `<system-reminder>` wrapper an instruction context carries — which wraps\n * content and cannot be separated from it — that line states the form's own\n * semantics, so the body states them as a caption instead of reprinting the\n * joined prose beside the sections it was split from.\n * @param props - Durable content, its source, and the locale seat.\n * @returns The snapshot context body, or the opaque body when unreadable.\n */\nexport function SnapshotBody({\n content,\n source,\n t,\n}: {\n content: ContextMessageNode[\"content\"];\n source: unknown;\n t: Translate;\n}): ReactNode {\n const sections = snapshotSections(source);\n /* v8 ignore next -- contextBody reads the sections before choosing this body. */\n if (sections === null) return <OpaqueBody content={content} source={source} t={t} />;\n return (\n <>\n <p className={css.catalogNotice} data-context-snapshot-supersedes>\n {t(\"message.context.snapshot.supersedes\")}\n </p>\n <dl className={css.sections} data-context-sections>\n {sections.map((section, index) => (\n <div key={index} className={css.section}>\n <dt className={css.sectionName}>{section.name}</dt>\n <dd className={css.sectionText}>{boundedText(section.text, t)}</dd>\n </div>\n ))}\n </dl>\n </>\n );\n}\n\n/**\n * `notice` form: what just happened, with the model-facing text beneath it.\n *\n * The one-line account also rides the collapsed row ({@link contextBody}), so a\n * notice is usually readable without expanding at all.\n * @param props - Durable content, its source, and the locale seat.\n * @returns The notice context body.\n */\nexport function NoticeBody({\n content,\n t,\n}: {\n content: ContextMessageNode[\"content\"];\n source: unknown;\n t: Translate;\n}): ReactNode {\n return <ModelFacingContent content={content} t={t} />;\n}\n\n/**\n * `relay` form: which agent sent this, then what it said.\n *\n * The sender is an opaque session id; it is shown as a field rather than a\n * label, because this client cannot resolve it to a title.\n * @param props - Durable content, its source, and the locale seat.\n * @returns The relay context body.\n */\nexport function RelayBody({\n content,\n source,\n t,\n}: {\n content: ContextMessageNode[\"content\"];\n source: unknown;\n t: Translate;\n}): ReactNode {\n const sender = relaySender(source);\n /* v8 ignore next -- contextBody resolves the sender before choosing this body. */\n if (sender === null) return <OpaqueBody content={content} source={source} t={t} />;\n return (\n <>\n <p className={css.relaySender} data-context-relay-sender>\n {t(\"message.context.relay.from\", { session: sender })}\n </p>\n <ModelFacingContent content={content} t={t} />\n </>\n );\n}\n\n/** The sending agent's session id, or null when the record does not name one. */\nfunction relaySender(source: unknown): string | null {\n const sender = asRecord(source)?.[\"senderSessionId\"];\n return typeof sender === \"string\" && sender !== \"\" ? sender : null;\n}\n\n/** One recalled session, as the durable source records it. */\ninterface RecalledSession {\n label: string;\n retained: number;\n omitted: number;\n truncated: boolean;\n}\n\n/** Recalled sessions read off the source, or null when the record is unusable. */\nfunction recalledSessions(source: unknown): RecalledSession[] | null {\n const record = asRecord(source);\n const list = record === null ? undefined : record[\"references\"];\n if (!Array.isArray(list)) return null;\n const sessions: RecalledSession[] = [];\n for (const item of list as readonly unknown[]) {\n const reference = asRecord(item);\n if (reference === null) return null;\n const label = reference[\"label\"];\n const retained = reference[\"retainedMessages\"];\n const omitted = reference[\"omittedMessages\"];\n const truncated = reference[\"truncated\"];\n // Completeness is the fact this card exists to report, so a reference that\n // cannot state it is not a readable recall — showing the label alone would\n // present a confident card over unknown loss.\n if (\n typeof label !== \"string\" ||\n label === \"\" ||\n typeof retained !== \"number\" ||\n typeof omitted !== \"number\" ||\n typeof truncated !== \"boolean\"\n )\n return null;\n sessions.push({ label, retained, omitted, truncated });\n }\n return sessions.length === 0 ? null : sessions;\n}\n\n/**\n * `recall` form: which sessions this material came from and how much of each\n * survived the read, then the material itself.\n *\n * Completeness is the fact a reader needs first: recalled context is bounded on\n * the way in, so a card that hid the omitted count would overstate what the\n * model received.\n * @param props - Durable content, its source, and the locale seat.\n * @returns The recall context body, or the opaque body when unreadable.\n */\nexport function RecallBody({\n content,\n source,\n t,\n}: {\n content: ContextMessageNode[\"content\"];\n source: unknown;\n t: Translate;\n}): ReactNode {\n const sessions = recalledSessions(source);\n if (sessions === null) return <OpaqueBody content={content} source={source} t={t} />;\n return (\n <>\n <ul className={css.recalls} data-context-recalls>\n {sessions.map((session, index) => (\n <li key={index} className={css.recall}>\n <span className={css.recallLabel}>{session.label}</span>\n <span className={css.recallCounts}>\n {t(\"message.context.recall.counts\", {\n retained: session.retained,\n omitted: session.omitted,\n })}\n </span>\n {session.truncated && (\n <span className={css.recallCounts}>{t(\"message.context.recall.truncated\")}</span>\n )}\n </li>\n ))}\n </ul>\n <ModelFacingContent content={content} t={t} />\n </>\n );\n}\n\n/** The one-line account a `notice` puts on its collapsed row, when it records one. */\nfunction noticeSummary(source: unknown): string | null {\n const summary = asRecord(source)?.[\"summary\"];\n return typeof summary === \"string\" && summary !== \"\" ? summary : null;\n}\n\n/**\n * Choose the body for one context node.\n *\n * Returns the form the body actually rendered as, which is not always the\n * declared one: a declared form whose fields are unreadable falls back to\n * opaque, and the caller labels the row with what it really shows.\n * `summary` is the collapsed row's one-line account, which only a `notice`\n * records: its whole point is being readable without expanding.\n * @param form - the producer-declared form projected onto the node.\n * @param props - durable content, its source, and the locale seat.\n * @returns the rendered form (null for opaque), its collapsed summary, and its body.\n */\nexport function contextBody(\n form: ContextMessageNode[\"form\"],\n props: { content: ContextMessageNode[\"content\"]; source: unknown; t: Translate },\n): { rendered: KnownContextForm | null; summary: string | null; body: ReactNode } {\n const opaque = { rendered: null, summary: null, body: <OpaqueBody {...props} /> };\n switch (form) {\n case \"instructions\":\n return instructionChanges(props.source) === null\n ? opaque\n : { rendered: \"instructions\", summary: null, body: <InstructionsBody {...props} /> };\n case \"catalog\":\n return catalogEntries(props.source) === null\n ? opaque\n : { rendered: \"catalog\", summary: null, body: <CatalogBody {...props} /> };\n case \"snapshot\":\n return snapshotSections(props.source) === null\n ? opaque\n : { rendered: \"snapshot\", summary: null, body: <SnapshotBody {...props} /> };\n case \"notice\": {\n const summary = noticeSummary(props.source);\n return summary === null\n ? opaque\n : { rendered: \"notice\", summary, body: <NoticeBody {...props} /> };\n }\n case \"relay\":\n return relaySender(props.source) === null\n ? opaque\n : { rendered: \"relay\", summary: null, body: <RelayBody {...props} /> };\n case \"recall\":\n return recalledSessions(props.source) === null\n ? opaque\n : { rendered: \"recall\", summary: null, body: <RecallBody {...props} /> };\n case null:\n return opaque;\n /* v8 ignore next 4 -- closed-union backstop; the compiler rejects a new\n KnownContextForm here rather than letting it degrade to opaque silently. */\n default: {\n const unreachable: never = form;\n throw new Error(`unreachable context form: ${String(unreachable)}`);\n }\n }\n}\n","import { useState } from \"react\";\nimport type { ContextMessageNode } from \"@deepseek-ai/dsh-client-runtime/client\";\nimport type { ChatViewSlotProps } from \"@deepseek-ai/dsh-client-ui-conversation/client\";\nimport { DisclosureRow, IconBrowseOutline16 } from \"@deepseek-ai/dsh-client-ui-primitives\";\nimport { contextBody } from \"./ContextBody.tsx\";\nimport css from \"./ContextInjectionRow.module.css\";\n\n/** Props for the logged non-user message presentation. */\nexport interface ContextInjectionRowProps {\n content: ContextMessageNode[\"content\"];\n source: ContextMessageNode[\"source\"];\n /** Role and producer name projected from the durable source. */\n provenance: ContextMessageNode[\"provenance\"];\n /** Producer-declared information form; null renders the opaque body. */\n form: ContextMessageNode[\"form\"];\n /** The owning view's locale seat, passed down as a plain prop. */\n t: ChatViewSlotProps[\"t\"];\n}\n\n/**\n * Render logged context with the Tool calls disclosure chrome from Figma.\n *\n * The header names the role the context plays and, beside it, the producer the\n * durable source identifies, so a reader can tell an injected skill catalog\n * from a workspace instruction file or a recalled session without expanding.\n * The expanded body follows the producer-declared form; an absent or unknown\n * form renders the opaque body.\n * @param props - Durable content, its projected producer role/name and form, and the locale seat.\n * @returns A collapsed context row with a bounded, form-specific body.\n */\nexport function ContextInjectionRow({\n content,\n source,\n provenance,\n form,\n t,\n}: ContextInjectionRowProps) {\n const [open, setOpen] = useState(false);\n // Resolved rather than declared: a form whose fields are unreadable renders\n // the opaque body, and the marker must say what the row actually shows.\n const { rendered, summary, body } = contextBody(form, { content, source, t });\n\n return (\n <DisclosureRow\n className={css.root}\n icon={<IconBrowseOutline16 size={14} />}\n chevronClassName={css.chevron}\n title={t(provenance.role === \"recall\" ? \"message.contextRecall\" : \"message.contextInjection\")}\n collapsedContent={\n provenance.label === null ? undefined : (\n /* ToolRow's separator shape: an aria-hidden dot, so the accessible name\n stays the two readable parts and the two disclosure rows expose one\n name shape. A source that names no producer drops the dot with it. */\n <>\n <span className={css.sep} aria-hidden />\n <span className={css.source} data-context-source>\n {provenance.label}\n </span>\n {summary !== null && (\n <>\n <span className={css.sep} aria-hidden />\n <span className={css.summary} data-context-summary>\n {summary}\n </span>\n </>\n )}\n </>\n )\n }\n keepContentWhenOpen\n open={open}\n expandable\n expandOnRowClick\n onToggle={() => {\n setOpen((value) => !value);\n }}\n >\n <div\n className={css.body}\n data-context-injection-body\n data-context-form={rendered ?? undefined}\n >\n {body}\n </div>\n </DisclosureRow>\n );\n}\n","// Shared time-label helpers for user/assistant IconActions rows.\n\nimport type { Translate } from \"@deepseek-ai/dsh-client-ui-slots\";\n\n/** The date-template share of the conversation dictionary the clock consumes. */\nexport type ClockTranslate = Translate<\"clock.md\" | \"clock.ymd\">;\n\n/** The elapsed-duration share of the conversation dictionary. */\nexport type RunDurationTranslate = Translate<\"duration.seconds\" | \"duration.minutes\">;\nfunction pad2(n: number): string {\n return String(n).padStart(2, \"0\");\n}\n\n/**\n * Local calendar-day epoch (ms at local midnight) for an instant.\n * @param ms - Unix epoch ms.\n * @returns Midnight of that local calendar day.\n */\nexport function startOfLocalDay(ms: number): number {\n const d = new Date(ms);\n d.setHours(0, 0, 0, 0);\n return d.getTime();\n}\n\n/**\n * Delay until the next local midnight after `ms` (at least 1ms).\n * @param ms - Unix epoch ms.\n * @returns Milliseconds until the following local midnight.\n */\nexport function msUntilNextLocalMidnight(ms: number): number {\n const next = new Date(ms);\n next.setHours(24, 0, 0, 0);\n return Math.max(next.getTime() - ms, 1);\n}\n\n/**\n * Localized elapsed-time label shared by running and settled turn chrome.\n * @param ms - Elapsed duration in milliseconds (negatives clamp to zero).\n * @param t - Translate seat supplying the duration templates.\n * @returns Display string in whole seconds.\n */\nexport function formatRunDuration(ms: number, t: RunDurationTranslate): string {\n const total = Math.max(0, Math.floor(ms / 1000));\n const minutes = Math.floor(total / 60);\n const seconds = total % 60;\n return minutes > 0\n ? t(\"duration.minutes\", { minutes, seconds: String(seconds).padStart(2, \"0\") })\n : t(\"duration.seconds\", { seconds });\n}\n\n/**\n * Sub-turn latency figure: one decimal under ten seconds, whole seconds\n * beyond. Unit-less so the locale template owns the second suffix.\n * @param ms - Latency in milliseconds (negatives clamp to zero).\n * @returns Display number in seconds without unit.\n */\nexport function formatLatencySeconds(ms: number): string {\n const s = Math.max(0, ms) / 1000;\n return s < 10 ? String(Math.round(s * 10) / 10) : String(Math.round(s));\n}\n\n/**\n * Decode-throughput figure: whole tokens from ten up, one decimal below.\n * @param tps - Tokens per second.\n * @returns Display number without unit.\n */\nexport function formatTokensPerSecond(tps: number): string {\n const clamped = Math.max(0, tps);\n return clamped >= 10 ? String(Math.round(clamped)) : String(Math.round(clamped * 10) / 10);\n}\n\n/**\n * Compact local timestamp for message IconActions. Same calendar day →\n * `HH:mm`; earlier this year → the `clock.md` date template + clock; other\n * years → the `clock.ymd` template + clock. Pure: the date templates arrive\n * through the caller's locale seat.\n * @param time - Unix epoch ms from the source session event.\n * @param t - translate seat supplying the `clock.md` / `clock.ymd` templates.\n * @param now - Reference instant for the day/year cut (defaults to wall clock).\n * @returns Date-aware clock string (24-hour, zero-padded time).\n */\nexport function formatMessageClock(\n time: number,\n t: ClockTranslate,\n now: number = Date.now(),\n): string {\n const d = new Date(time);\n const n = new Date(now);\n const clock = `${pad2(d.getHours())}:${pad2(d.getMinutes())}`;\n if (\n d.getFullYear() === n.getFullYear() &&\n d.getMonth() === n.getMonth() &&\n d.getDate() === n.getDate()\n ) {\n return clock;\n }\n const params = { y: d.getFullYear(), m: d.getMonth() + 1, d: d.getDate() };\n const md = d.getFullYear() === n.getFullYear() ? t(\"clock.md\", params) : t(\"clock.ymd\", params);\n return `${md} ${clock}`;\n}\n","// Component-local calendar-day tick: memoized message rows keep stable props\n// across midnight, so the IconActions clock needs a local day seat that\n// re-fires at the next local midnight without reaching for framework hooks.\n\nimport { useEffect, useState } from \"react\";\nimport { msUntilNextLocalMidnight, startOfLocalDay } from \"./message-chrome.ts\";\n\n/**\n * Local calendar-day epoch that advances at each local midnight.\n * @returns Midnight ms for the current local day; updates after the boundary.\n */\nexport function useCalendarDay(): number {\n const [day, setDay] = useState(() => startOfLocalDay(Date.now()));\n useEffect(() => {\n let timer: ReturnType<typeof setTimeout>;\n const arm = (): void => {\n const now = Date.now();\n setDay(startOfLocalDay(now));\n timer = setTimeout(arm, msUntilNextLocalMidnight(now));\n };\n timer = setTimeout(arm, msUntilNextLocalMidnight(Date.now()));\n return () => {\n clearTimeout(timer);\n };\n }, []);\n return day;\n}\n","// Shared IconActions chrome for user and assistant messages: copy\n// live, optional branch wiring, and an optional date-aware clock.\n\nimport { useCallback, useEffect, useId, useRef, useState, type ReactNode } from \"react\";\nimport {\n IconBranchOutline16,\n IconCheckOutline16,\n IconCopyOutline16,\n IconEditOutline16,\n IconRefreshOutline16,\n Tooltip,\n writeClipboard,\n} from \"@deepseek-ai/dsh-client-ui-primitives\";\nimport type { ChatViewSlotProps } from \"@deepseek-ai/dsh-client-ui-conversation/client\";\nimport {\n formatLatencySeconds,\n formatMessageClock,\n formatRunDuration,\n formatTokensPerSecond,\n} from \"./message-chrome.ts\";\nimport { useCalendarDay } from \"./use-calendar-day.ts\";\nimport css from \"./MessageIconActions.module.css\";\n\nexport interface MessageIconActionsProps {\n /** Plain text the copy action writes. */\n text: string;\n /** Unix epoch ms for the clock label; omitted for transient messages. */\n time?: number | undefined;\n /** Turn wall time in ms, appended to the clock as `· Ran for 15s`; omitted when the turn's start is unknown. */\n runMs?: number | undefined;\n /** Turn first-step TTFT in ms, appended as `· TTFT 1.2s`; omitted when unrecorded. */\n ttftMs?: number | undefined;\n /** Turn decode throughput, appended as `· 34 tok/s`; omitted when unrecorded. */\n tokensPerSecond?: number | undefined;\n /** Clock before icons (user) or after (assistant). */\n clock: \"start\" | \"end\";\n /** Fork the session at this message; omission hides the branch action. */\n onBranch?: (() => void) | undefined;\n /** The message is not a completed transcript tail, so branch stays visible but unavailable. */\n branchUnavailable?: boolean | undefined;\n /** Parent layout class composed onto the actions row. */\n className?: string | undefined;\n /**\n * Slot-rendered actions owned by independent plugins, placed between the\n * built-in copy and branch controls.\n */\n extraActions?: ReactNode;\n /** Edit this message block in place (session-editor). */\n onEdit?: (() => void) | undefined;\n /** Retry this turn in place (session-editor). */\n onRetry?: (() => void) | undefined;\n /** The owning view's locale seat, passed down as a plain prop. */\n t: ChatViewSlotProps[\"t\"];\n}\n\n/**\n * Copy / branch (/ clock) IconActions row shared by user and assistant chrome.\n * @param props - Copy text, event time, clock side, branch callback, className.\n * @returns The actions row element.\n */\nexport function MessageIconActions({\n text,\n time,\n runMs,\n ttftMs,\n tokensPerSecond,\n clock,\n onBranch,\n branchUnavailable = false,\n className,\n extraActions,\n onEdit,\n onRetry,\n t,\n}: MessageIconActionsProps) {\n const day = useCalendarDay();\n const reasonId = useId();\n // Same success chrome as CodeBlock: a short check swap after the write,\n // gated so re-clicks during the window neither re-copy nor stack timers.\n const [copied, setCopied] = useState(false);\n const copyPending = useRef(false);\n const copyTimer = useRef<number | null>(null);\n const copyEpoch = useRef(0);\n useEffect(\n () => () => {\n copyEpoch.current += 1;\n copyPending.current = false;\n if (copyTimer.current !== null) clearTimeout(copyTimer.current);\n },\n [],\n );\n const onCopy = useCallback(() => {\n if (copied || copyPending.current) return;\n const epoch = copyEpoch.current;\n copyPending.current = true;\n void writeClipboard(text).then((ok) => {\n if (epoch !== copyEpoch.current) return;\n copyPending.current = false;\n if (!ok) return;\n setCopied(true);\n copyTimer.current = window.setTimeout(() => {\n copyTimer.current = null;\n setCopied(false);\n }, 1000);\n });\n }, [copied, text]);\n // The dot is decorative and stays hidden, but its margins separate the\n // readings only on screen: without the flanking spaces a reader hears one\n // run-on string (\"Ran for 13sTTFT 0.2s12 tok/s\") instead of three facts.\n const clockEl =\n time === undefined ? null : (\n <span className={clock === \"start\" ? css.timeStart : css.timeEnd}>\n {formatMessageClock(time, t, day)}\n {runMs !== undefined && (\n <>\n {\" \"}\n <span className={css.runTimeDot} aria-hidden>\n ·\n </span>{\" \"}\n {t(\"message.ranFor\", { duration: formatRunDuration(runMs, t) })}\n </>\n )}\n {ttftMs !== undefined && (\n <>\n {\" \"}\n <span className={css.runTimeDot} aria-hidden>\n ·\n </span>{\" \"}\n {t(\"message.ttft\", { seconds: formatLatencySeconds(ttftMs) })}\n </>\n )}\n {tokensPerSecond !== undefined && (\n <>\n {\" \"}\n <span className={css.runTimeDot} aria-hidden>\n ·\n </span>{\" \"}\n {t(\"message.tokensPerSecond\", { tps: formatTokensPerSecond(tokensPerSecond) })}\n </>\n )}\n </span>\n );\n return (\n <div className={className === undefined ? css.actions : `${css.actions} ${className}`}>\n {clock === \"start\" ? clockEl : null}\n <Tooltip label={copied ? t(\"copied\" as never) : t(\"copy\" as never)} side=\"bottom\">\n <button\n type=\"button\"\n className={css.action}\n aria-label={copied ? t(\"copied\" as never) : t(\"copy\" as never)}\n onClick={onCopy}\n >\n {copied ? <IconCheckOutline16 /> : <IconCopyOutline16 />}\n </button>\n </Tooltip>\n {extraActions}\n {onEdit !== undefined && (\n <Tooltip label=\"编辑\" side=\"bottom\">\n <button type=\"button\" className={css.action} aria-label=\"编辑\" onClick={onEdit}>\n <IconEditOutline16 />\n </button>\n </Tooltip>\n )}\n {onRetry !== undefined && (\n <Tooltip label=\"重试此回合\" side=\"bottom\">\n <button type=\"button\" className={css.action} aria-label=\"重试此回合\" onClick={onRetry}>\n <IconRefreshOutline16 />\n </button>\n </Tooltip>\n )}\n {onBranch !== undefined && (\n <Tooltip\n label={branchUnavailable ? t(\"message.branchUnavailable\") : t(\"message.branch\")}\n side=\"bottom\"\n >\n {/* Native disabled buttons do not deliver the hover/focus events Tooltip needs. */}\n <button\n type=\"button\"\n className={css.action}\n aria-label={t(\"message.branch\")}\n aria-disabled={branchUnavailable || undefined}\n aria-describedby={branchUnavailable ? reasonId : undefined}\n data-unavailable={branchUnavailable || undefined}\n onClick={branchUnavailable ? undefined : onBranch}\n >\n <IconBranchOutline16 />\n </button>\n </Tooltip>\n )}\n {onBranch !== undefined && branchUnavailable && (\n <span id={reasonId} className={css.visuallyHidden}>\n {t(\"message.branchUnavailable\")}\n </span>\n )}\n {clock === \"end\" ? clockEl : null}\n </div>\n );\n}\n","/**\n * 消息编辑弹窗:与 dsh settings 同风格的 Modal(@deepseek-ai/dsh-client-ui-primitives)。\n * 输入框复用 composer-card 的视觉(InputBar 同款 border/radius/surface/阴影\n * token)与自动增长交互。保存成功后关闭;失败保持打开。\n */\n\nimport { useRef, useState } from \"react\";\nimport { Button, Modal } from \"@deepseek-ai/dsh-client-ui-primitives\";\nimport type { EditableMessageBlock } from \"../../shared.ts\";\nimport css from \"./MessageEditDialog.module.css\";\n\nconst BLOCK_TITLE: Record<EditableMessageBlock[\"kind\"], string> = {\n user: \"编辑用户消息\",\n \"assistant.reasoning\": \"编辑助手思考\",\n \"assistant.response\": \"编辑助手回复\",\n};\n\n/** 编辑弹窗:调用 onSave 保存;返回 true 关闭,false 保持打开。 */\nexport function MessageEditDialog({\n block,\n onSave,\n onClose,\n}: {\n block: EditableMessageBlock;\n onSave: (text: string) => Promise<boolean>;\n onClose: () => void;\n}) {\n const [text, setText] = useState(block.text);\n const [saving, setSaving] = useState(false);\n const inputRef = useRef<HTMLTextAreaElement | null>(null);\n\n /** composer-card 式自动增长:高度随内容(scrollHeight)自适应。 */\n const autosize = (): void => {\n const el = inputRef.current;\n if (el === null) return;\n el.style.height = \"auto\";\n el.style.height = `${el.scrollHeight}px`;\n };\n\n const save = (): void => {\n if (saving) return;\n setSaving(true);\n void onSave(text).then((applied) => {\n if (applied) onClose();\n else setSaving(false);\n });\n };\n\n return (\n <Modal\n open\n onClose={onClose}\n title={BLOCK_TITLE[block.kind]}\n closeLabel=\"关闭\"\n footer={\n <div className={css.actions}>\n <Button variant=\"outline\" onClick={onClose} disabled={saving}>\n 取消\n </Button>\n <Button variant=\"primary\" onClick={save} disabled={saving}>\n {saving ? \"保存中…\" : \"保存\"}\n </Button>\n </div>\n }\n >\n <textarea\n ref={inputRef}\n className={css.input}\n value={text}\n onChange={(event) => {\n setText(event.target.value);\n autosize();\n }}\n autoFocus\n rows={4}\n />\n </Modal>\n );\n}\n","// MessageItem: simple chat nodes — user and consumed-steering bubbles\n// (right-aligned, with clock + copy IconActions; branch lives only under\n// assistant answers), pending steering (copy only), context injection,\n// compaction marker, retry disclosure, and unknown-surface JSON rows.\n\nimport { memo, useEffect, useMemo, useState } from \"react\";\nimport type { ReactNode } from \"react\";\nimport type { InjectFace } from \"@deepseek-ai/dsh-client-ui-slots\";\nimport { Button, Modal } from \"@deepseek-ai/dsh-client-ui-primitives\";\nimport type {\n ModelRetryNode,\n TurnErrorNode,\n UserMessageNode,\n} from \"@deepseek-ai/dsh-client-runtime/client\";\nimport { JsonBlock, MessageText, StateDot } from \"@deepseek-ai/dsh-client-ui-primitives\";\nimport type {\n ChatNodeViewProps,\n ChatViewSlotProps,\n RenderMessageImages,\n} from \"@deepseek-ai/dsh-client-ui-conversation/client\";\nimport { CompactionItem } from \"./CompactionItem.tsx\";\nimport { ContextInjectionRow } from \"./ContextInjectionRow.tsx\";\nimport { MessageIconActions } from \"./MessageIconActions.tsx\";\nimport { MessageEditDialog } from \"./MessageEditDialog.tsx\";\nimport css from \"./MessageItem.module.css\";\nimport type { EditableMessageBlock } from \"../../shared.ts\";\nimport type { SessionEditorFace } from \"../controller.ts\";\n\ntype UserImage = Extract<UserMessageNode[\"content\"][number], { type: \"image\" }>;\n\nfunction contentParts(content: readonly unknown[]): {\n text: string;\n images: { attachment: UserImage[\"attachment\"] }[];\n rest: unknown[];\n} {\n const texts: string[] = [];\n const images: { attachment: UserImage[\"attachment\"] }[] = [];\n const rest: unknown[] = [];\n for (const block of content) {\n const b = block as { type?: string; text?: string; attachment?: unknown };\n if (b.type === \"text\" && typeof b.text === \"string\") texts.push(b.text);\n else if (b.type === \"image\" && b.attachment !== undefined) {\n images.push({ attachment: (b as UserImage).attachment });\n } else rest.push(block);\n }\n return { text: texts.join(\"\"), images, rest };\n}\n\nfunction retrySeconds(milliseconds: number): number {\n return Math.max(1, Math.ceil(milliseconds / 1_000));\n}\n\ninterface RetryCountdown {\n deadline: number;\n seconds: number;\n}\n\nfunction ModelRetryItem({\n node,\n active,\n t,\n}: {\n node: ModelRetryNode;\n active: boolean;\n t: ChatViewSlotProps[\"t\"];\n}) {\n // Anchor the host-scheduled delay to this browser's first render of the\n // retry node. Host event time and Date.now() may belong to different clocks.\n const deadline = useMemo(() => Date.now() + node.delayMs, [node.delayMs, node.seq]);\n const scheduledSeconds = retrySeconds(node.delayMs);\n const maximum = node.mode === \"normal\" ? node.maxRetries : \"∞\";\n const [countdown, setCountdown] = useState<RetryCountdown>(() => ({\n deadline,\n seconds: retrySeconds(deadline - Date.now()),\n }));\n const remainingSeconds =\n countdown.deadline === deadline ? countdown.seconds : retrySeconds(deadline - Date.now());\n\n useEffect(() => {\n if (!active) return;\n const updateCountdown = (): number => {\n const next = retrySeconds(deadline - Date.now());\n setCountdown((current) =>\n current.deadline === deadline && current.seconds === next\n ? current\n : { deadline, seconds: next },\n );\n return next;\n };\n if (updateCountdown() === 1) return;\n const timer = window.setInterval(() => {\n if (updateCountdown() === 1) window.clearInterval(timer);\n }, 250);\n return () => {\n window.clearInterval(timer);\n };\n }, [active, deadline]);\n\n const label = active\n ? t(\"message.retry.active\")\n : node.retryState === \"cancelled\"\n ? t(\"message.retry.cancelled\")\n : node.retryState === \"started\"\n ? t(\"message.retry.started\")\n : t(\"message.retry.scheduled\");\n const seconds = active ? remainingSeconds : scheduledSeconds;\n\n return (\n <details className={css.retryRow} data-active={active || undefined}>\n <summary className={css.retrySummary}>\n <span className={css.retryText} role=\"status\">\n {t(\"message.retry.status\", { label, retry: node.retry, maximum, seconds })}\n </span>\n </summary>\n <div className={css.retryDetails}>\n <div>\n <span className={css.retryDetailLabel}>{t(\"message.retry.delay\")}</span>\n {Math.round(node.delayMs)}ms\n </div>\n <div>\n <span className={css.retryDetailLabel}>{t(\"message.retry.failure\")}</span>\n {node.failure.message}\n </div>\n </div>\n </details>\n );\n}\n\n/** Persistent, turn-positioned feedback for a terminal failure. */\nfunction TurnErrorItem({ node, t }: { node: TurnErrorNode; t: ChatViewSlotProps[\"t\"] }) {\n return (\n <div className={css.turnErrorRow} role=\"status\">\n <StateDot state=\"error\" className={css.turnErrorDot} />\n <div className={css.turnErrorCopy}>\n <span className={css.turnErrorTitle}>{t(\"message.turnError\")}</span>\n <span className={css.turnErrorMessage}>{node.message}</span>\n </div>\n {node.code !== undefined && <code className={css.turnErrorCode}>{node.code}</code>}\n </div>\n );\n}\n\n/** Persistent, turn-positioned notice for a turn ended at the output-token cap. */\nfunction TurnMaxTokensItem({ t }: { t: ChatViewSlotProps[\"t\"] }) {\n return (\n <div className={css.turnErrorRow} role=\"status\">\n <StateDot state=\"warning\" className={css.turnErrorDot} />\n <div className={css.turnErrorCopy}>\n <span className={css.maxTokensTitle}>{t(\"message.maxTokens\")}</span>\n <span className={css.turnErrorMessage}>{t(\"message.maxTokens.hint\")}</span>\n </div>\n </div>\n );\n}\n\n/**\n * Display projection of reference forms in a user bubble (free geometry — no\n * textarea alignment constraint here); everything else stays plain text. The\n * logged model text remains the single truth; this is presentation only.\n * Plain-text `/name` / `@name` word-boundary tokens decorate (the sent text\n * IS the reference — the bubble uses the same plainest token\n * scan as the composer, minus the lexicon: sent tokens were validated at\n * compose time, so shape alone decorates).\n */\nfunction projectUserText(text: string): ReactNode {\n const re = /(^|\\s)([/@][\\w-]+)(?=\\s|$)/g;\n const parts: ReactNode[] = [];\n let cursor = 0;\n let m: RegExpExecArray | null;\n while ((m = re.exec(text)) !== null) {\n const tokenStart = m.index + (m[1]?.length ?? 0);\n const label = m[2] ?? \"\";\n if (tokenStart > cursor)\n parts.push(<MessageText key={cursor} text={text.slice(cursor, tokenStart)} />);\n parts.push(\n <span\n key={tokenStart}\n className={css.refChip}\n data-ref-chip={label.startsWith(\"@\") ? \"subagent\" : \"skill\"}\n >\n {label}\n </span>,\n );\n cursor = tokenStart + label.length;\n }\n if (parts.length === 0) return <MessageText text={text} />;\n if (cursor < text.length) parts.push(<MessageText key={cursor} text={text.slice(cursor)} />);\n return <>{parts}</>;\n}\n\n/** Right-aligned bubble shared by user and steering rows. */\nfunction UserStyleBubble({\n content,\n renderMessageImages,\n actions,\n pending = false,\n t,\n}: {\n content: readonly unknown[];\n renderMessageImages: RenderMessageImages;\n /** Optional IconActions (or similar) below the bubble; receives the joined text. */\n actions?: (text: string) => ReactNode;\n /** Whether this is the Host-authoritative pre-admission steering projection. */\n pending?: boolean;\n t: ChatViewSlotProps[\"t\"];\n}): ReactNode {\n const { text, images, rest } = contentParts(content);\n const truncated = (total: number): string => t(\"json.truncated\", { total });\n const showBubble = text !== \"\" || rest.length > 0;\n return (\n <div className={css.userRow} data-pending-steering={pending || undefined} data-time-hover-root>\n <div className={css.userStack}>\n {renderMessageImages({ images, align: \"end\" })}\n {showBubble && (\n <div className={css.bubble}>\n {projectUserText(text)}\n {rest.map((block, i) => (\n <JsonBlock\n key={i}\n label={t(\"message.extraBlock\")}\n payload={block}\n truncatedLabel={truncated}\n />\n ))}\n </div>\n )}\n </div>\n {actions?.(text)}\n </div>\n );\n}\n\n/**\n * Render one Host-authoritative pending steering item with the same visual\n * language as its eventual durable transcript node.\n * @param props - Pending message content and conversation translator.\n * @returns the pending steering bubble.\n */\nexport function PendingSteeringBubble({\n content,\n renderMessageImages,\n t,\n}: {\n content: readonly unknown[];\n renderMessageImages: RenderMessageImages;\n t: ChatViewSlotProps[\"t\"];\n}): ReactNode {\n return (\n <UserStyleBubble\n content={content}\n renderMessageImages={renderMessageImages}\n pending\n t={t}\n actions={(text) => (\n <MessageIconActions text={text} clock=\"start\" className={css.actions} t={t} />\n )}\n />\n );\n}\n\n/** User and admitted-steering keyed Chat renderer. */\nexport const UserMessageNodeView = memo(function UserMessageNodeView({\n node,\n renderMessageImages,\n t,\n edit,\n retry,\n}: ChatNodeViewProps<\"user\" | \"steering\"> & InjectFace<SessionEditorFace>) {\n const data = node.data;\n const [editing, setEditing] = useState<EditableMessageBlock | null>(null);\n const [confirmingRetry, setConfirmingRetry] = useState(false);\n const turnLocation =\n node.location.kind === \"turn\" || node.location.kind === \"step\" ? node.location.turn : undefined;\n const turn = turnLocation?.turn;\n // 重试只对已闭合轮次开放(未闭合/无闭合边界的轮次服务端无法重放)。\n const retryable = turnLocation?.status === \"closed\";\n // 编辑目标:第一个文本块(与 Timeline 编辑面的 blockIndex 对齐)。\n const textBlockIndex = data.content.findIndex(\n (block) => (block as { type?: string }).type === \"text\",\n );\n const textBlock =\n textBlockIndex === -1 ? undefined : (data.content[textBlockIndex] as { text?: string });\n const onEdit =\n textBlock === undefined || turn === undefined\n ? undefined\n : () => {\n setEditing({\n key: `${node.anchorSeq}:${String(textBlockIndex)}`,\n turn,\n eventSeq: node.anchorSeq,\n blockIndex: textBlockIndex,\n kind: \"user\",\n text: textBlock.text ?? \"\",\n time: data.time,\n });\n };\n // 重试先弹确认(就地编辑会抛弃该回合及其后的内容)。\n const onRetry =\n retryable && turn !== undefined\n ? () => {\n setConfirmingRetry(true);\n }\n : undefined;\n return (\n <>\n {editing !== null && (\n <MessageEditDialog\n block={editing}\n onSave={(text) => edit(editing, text, \"truncate\")}\n onClose={() => setEditing(null)}\n />\n )}\n {confirmingRetry && turn !== undefined && (\n <Modal\n open\n onClose={() => setConfirmingRetry(false)}\n title=\"重试回合\"\n closeLabel=\"关闭\"\n description={`将重新生成第 ${turn} 轮的回复,并抛弃该回合之后的内容。`}\n footer={\n <div className={css.confirmActions}>\n <Button variant=\"outline\" onClick={() => setConfirmingRetry(false)}>\n 取消\n </Button>\n <Button\n variant=\"primary\"\n onClick={() => {\n setConfirmingRetry(false);\n void retry(turn, \"truncate\");\n }}\n >\n 确认重试\n </Button>\n </div>\n }\n />\n )}\n <UserStyleBubble\n content={data.content}\n renderMessageImages={renderMessageImages}\n t={t}\n actions={(text) => (\n <MessageIconActions\n text={text}\n time={data.time}\n clock=\"start\"\n className={css.actions}\n t={t}\n onEdit={onEdit}\n onRetry={onRetry}\n />\n )}\n />\n </>\n );\n});\n\n/** Injected-context keyed Chat renderer. */\nexport const ContextMessageNodeView = memo(function ContextMessageNodeView({\n node,\n t,\n}: ChatNodeViewProps<\"context\">) {\n const data = node.data;\n return (\n <ContextInjectionRow\n content={data.content}\n source={data.source}\n provenance={data.provenance}\n form={data.form}\n t={t}\n />\n );\n});\n\n/** Automatic compaction keyed Chat renderer. */\nexport const CompactionNodeView = memo(function CompactionNodeView({\n node,\n t,\n}: ChatNodeViewProps<\"compaction\">) {\n return <CompactionItem node={node.data} t={t} />;\n});\n\n/** Correlated retry-chain keyed Chat renderer. */\nexport const RetryNodeView = memo(function RetryNodeView({\n node,\n t,\n}: ChatNodeViewProps<\"model-retry\">) {\n const data = node.data;\n return (\n <ModelRetryItem node={data.current} active={data.current.retryState === \"scheduled\"} t={t} />\n );\n});\n\n/** Terminal turn-error keyed Chat renderer. */\nexport const TurnErrorNodeView = memo(function TurnErrorNodeView({\n node,\n t,\n}: ChatNodeViewProps<\"turn-error\">) {\n return <TurnErrorItem node={node.data} t={t} />;\n});\n\n/** Max-tokens turn-end notice keyed Chat renderer. */\nexport const TurnMaxTokensNodeView = memo(function TurnMaxTokensNodeView({\n t,\n}: ChatNodeViewProps<\"turn-max-tokens\">) {\n return <TurnMaxTokensItem t={t} />;\n});\n\n/** Explicit unknown-surface keyed Chat renderer. */\nexport const UnknownNodeView = memo(function UnknownNodeView({\n node,\n t,\n}: ChatNodeViewProps<\"unknown\">) {\n const data = node.data;\n return (\n <div className={css.contextRow}>\n <JsonBlock\n label={t(\"message.unknownSurface\", { type: data.type })}\n payload={data.data}\n truncatedLabel={(total) => t(\"json.truncated\", { total })}\n />\n </div>\n );\n});\n","import type { AssistantBlock } from \"@deepseek-ai/dsh-client-runtime/client\";\n\n/**\n * Collect visible prose from one Assistant lifecycle.\n * @param blocks - Assistant content blocks.\n * @returns concatenated text blocks.\n */\nexport function assistantText(blocks: readonly AssistantBlock[]): string {\n return blocks.flatMap((block) => (block.kind === \"text\" ? [block.text] : [])).join(\"\");\n}\n","import { memo } from \"react\";\nimport type { InjectFace } from \"@deepseek-ai/dsh-client-ui-slots\";\nimport type { ChatNodeViewProps } from \"@deepseek-ai/dsh-client-ui-conversation/client\";\nimport { MessageIconActions } from \"./MessageIconActions.tsx\";\nimport { assistantText } from \"./turn-assistant.ts\";\nimport css from \"./TurnTailNodeView.module.css\";\nimport type { SessionEditorFace } from \"../controller.ts\";\n\ntype TurnTailNodeViewProps = ChatNodeViewProps<\"turn-tail\"> & InjectFace<SessionEditorFace>;\n\n/**\n * Turn-local actions over the Location index, independent of Assistant\n * placement.\n *\n * 注意:本 renderer 是 `conversation.chat.node` 的 shadow 注册(priority -1),\n * 而 `renderSlotChain` / `renderSlot` 只在注册声明了对应 children 时由 slot\n * 链传入——turnTail / assistant-actions 的 children 已被上游(ui-conversation)\n * 声明,shadow 注册再声明会抛「already declared」,因此这里不消费子 slot。\n *\n * 编辑 / 重试按钮只挂在 **user 消息**(UserMessageNodeView)上,助手尾部不\n * 提供(避免对未闭合/无 user 输入的轮次误触)。\n */\nexport const TurnTailNodeView = memo(function TurnTailNodeView({\n node,\n forkAt,\n t,\n useSession,\n}: TurnTailNodeViewProps) {\n const data = node.data;\n const hasLaterChatNode = useSession(\n (snapshot) => snapshot.chat.locations.getTurn(data.turn).at(-1) !== node.key,\n );\n const turn =\n node.location.kind === \"turn\" || node.location.kind === \"step\" ? node.location.turn : undefined;\n if (turn === undefined) return null;\n const closing = data.closing;\n const tail = null;\n if (closing === null) return tail === null ? null : <div className={css.root}>{tail}</div>;\n const runMs =\n turn.start === undefined || turn.end === undefined\n ? undefined\n : Math.max(0, turn.end.time - turn.start.time);\n return (\n <div className={css.root} data-turn-tail={data.turn} data-time-hover-root>\n <MessageIconActions\n text={assistantText(closing.blocks)}\n time={closing.time}\n runMs={runMs}\n ttftMs={data.ttftMs}\n tokensPerSecond={data.tokensPerSecond}\n clock=\"end\"\n onBranch={() => {\n forkAt(closing.finalNode.seq);\n }}\n branchUnavailable={data.branchUnavailable || hasLaterChatNode}\n className={css.actions}\n t={t}\n />\n </div>\n );\n});\n","/**\n * Register this package's chat-node renderers behind the keyed\n * `conversation.chat.node` seat. Every key is re-registered at `priority: -1`\n * so the lowest priority wins and the upstream renderers are shadowed without\n * touching `@deepseek-ai/*`. The per-session editor face is injected so the\n * copied renderers can drive edit / retry directly.\n */\n\nimport type { Context } from \"@deepseek-ai/cordis\";\nimport type { SessionId } from \"@deepseek-ai/dsh-client-runtime/client\";\nimport \"@deepseek-ai/dsh-client-ui-conversation/client\";\nimport { AssistantNodeView } from \"./AssistantNodeView.tsx\";\nimport { CommandNodeView, ManualCompactionNodeView } from \"./CommandNodeView.tsx\";\nimport {\n CompactionNodeView,\n ContextMessageNodeView,\n RetryNodeView,\n TurnErrorNodeView,\n TurnMaxTokensNodeView,\n UnknownNodeView,\n UserMessageNodeView,\n} from \"./MessageItem.tsx\";\nimport { TurnTailNodeView } from \"./TurnTailNodeView.tsx\";\nimport type { SessionEditorController } from \"../controller.ts\";\n\n/** `conversation` 字典命名空间(与上游一致)。 */\nconst NS = \"conversation\";\n\n/** 注册全部 chat-node key;priority -1 替换上游渲染。 */\nexport function registerChatNodeRenderers(\n ctx: Context,\n controllerFor: (sessionId: SessionId) => SessionEditorController,\n): void {\n const inject = (sessionId: SessionId) => controllerFor(sessionId).face;\n\n ctx.slots.register(\n { name: \"conversation.chat.node\", key: \"user\", locale: NS, priority: -1, inject },\n UserMessageNodeView,\n );\n ctx.slots.register(\n { name: \"conversation.chat.node\", key: \"steering\", locale: NS, priority: -1, inject },\n UserMessageNodeView,\n );\n ctx.slots.register(\n { name: \"conversation.chat.node\", key: \"context\", locale: NS, priority: -1, inject },\n ContextMessageNodeView,\n );\n ctx.slots.register(\n { name: \"conversation.chat.node\", key: \"assistant-step\", locale: NS, priority: -1, inject },\n AssistantNodeView,\n );\n ctx.slots.register(\n // command / turn-tail 的 children 由上游声明(commandview / turnTail /\n // assistant-actions);shadow 注册不重复声明,仅替换渲染器。\n { name: \"conversation.chat.node\", key: \"command\", locale: NS, priority: -1, inject } as never,\n CommandNodeView as never,\n );\n ctx.slots.register(\n { name: \"conversation.chat.node\", key: \"manual-compaction\", locale: NS, priority: -1, inject },\n ManualCompactionNodeView,\n );\n ctx.slots.register(\n { name: \"conversation.chat.node\", key: \"compaction\", locale: NS, priority: -1, inject },\n CompactionNodeView,\n );\n ctx.slots.register(\n { name: \"conversation.chat.node\", key: \"model-retry\", locale: NS, priority: -1, inject },\n RetryNodeView,\n );\n ctx.slots.register(\n { name: \"conversation.chat.node\", key: \"turn-error\", locale: NS, priority: -1, inject },\n TurnErrorNodeView,\n );\n ctx.slots.register(\n { name: \"conversation.chat.node\", key: \"turn-max-tokens\", locale: NS, priority: -1, inject },\n TurnMaxTokensNodeView,\n );\n ctx.slots.register(\n // 见 command:turnTail / assistant-actions 的 children 由上游声明。\n { name: \"conversation.chat.node\", key: \"turn-tail\", locale: NS, priority: -1, inject } as never,\n TurnTailNodeView as never,\n );\n ctx.slots.register(\n { name: \"conversation.chat.node\", key: \"unknown\", locale: NS, priority: -1, inject },\n UnknownNodeView,\n );\n}\n","/**\n * 会话头部「清洗会话」入口。\n *\n * 仅当会话历史加载失败(会话 snapshot 的 `openState === \"error\"`)时渲染:\n * 点击调用服务端 cleanse,把该会话的 sourceEventSeqs / surfaceOp /\n * shadowedRange 坐标一次性重写为稠密空间,成功后客户端 resync 重新加载\n * 历史。注入面来自 `SessionEditorFace`(hooks → `useSessionEditor`,\n * 方法 → `cleanse`)。\n */\n\nimport { useCallback, useState, type ReactElement } from \"react\";\nimport { Button, IconRefreshOutline16 } from \"@deepseek-ai/dsh-client-ui-primitives\";\nimport type { SessionEditorState } from \"./controller.ts\";\n\nexport interface CleanseSessionActionProps {\n /** inject hooks:订阅 sessionEditor 状态。 */\n useSessionEditor: <S>(sel: (s: SessionEditorState) => S) => S;\n /** inject face:发起清洗。 */\n cleanse: () => Promise<boolean>;\n}\n\n/**\n * 历史加载失败时显示「清洗会话」按钮。\n * @param props - 注入的 selector 钩子与清洗方法。\n * @returns 按钮元素;会话未处于错误状态时返回 null。\n */\nexport function CleanseSessionAction({\n useSessionEditor,\n cleanse,\n}: CleanseSessionActionProps): ReactElement | null {\n const openError = useSessionEditor((s) => s.sessionOpenError);\n const cleansing = useSessionEditor((s) => s.pending === \"cleanse\");\n const [busy, setBusy] = useState(false);\n const onClick = useCallback(() => {\n setBusy(true);\n void cleanse().finally(() => setBusy(false));\n }, [cleanse]);\n if (!openError) return null;\n const working = busy || cleansing;\n return (\n <Button\n variant=\"outline\"\n size=\"sm\"\n icon={<IconRefreshOutline16 />}\n onClick={onClick}\n disabled={working}\n title=\"清洗会话:把 provenance 坐标重写为稠密空间,修复历史加载失败\"\n >\n {working ? \"清洗中…\" : \"清洗会话\"}\n </Button>\n );\n}\n","/**\n * Session Editor browser half: the chat-node renderers that replace the\n * upstream `conversation.chat.node` registrations (priority shadow) so the\n * edit / retry entry points render directly in the message actions row.\n */\n\nimport type { ClientContext, SessionId } from \"@deepseek-ai/dsh-client-runtime/client\";\nimport type {} from \"@deepseek-ai/dsh-client-ui-conversation/client\";\nimport { SessionEditorController } from \"./controller.ts\";\nimport { registerChatNodeRenderers } from \"./chat-node/register.ts\";\nimport { CleanseSessionAction } from \"./cleanse-session-action.tsx\";\n\nexport const inject = [\"slots\", \"conversation\", \"connection\", \"sessions\"];\n\n/** 注册 UI 贡献 + chat-node renderer,共享同一 per-session controller。 */\nexport function apply(ctx: ClientContext): void {\n const controllers = new Map<SessionId, SessionEditorController>();\n const controllerFor = (sessionId: SessionId): SessionEditorController => {\n let controller = controllers.get(sessionId);\n if (controller === undefined) {\n controller = new SessionEditorController(ctx, sessionId);\n controllers.set(sessionId, controller);\n }\n return controller;\n };\n\n ctx.on(\"connection/reset\", () => {\n for (const controller of controllers.values()) void controller.load();\n });\n\n // 替换整个 conversation.chat.node:priority -1 最低渲染,shadow 上游注册。\n registerChatNodeRenderers(ctx, controllerFor);\n\n // 会话头部「清洗会话」入口:仅历史加载失败(openState === \"error\")时\n // 显示。header.actions 是 list 槽(注册需 id),上游未注册组件——这里是\n // 纯新增,无 shadow 冲突;priority -1 与其它注入面一致。\n ctx.slots.register(\n {\n name: \"conversation.session.header.actions\",\n id: \"session-editor.cleanse\",\n priority: -1,\n inject: (sessionId: SessionId) => controllerFor(sessionId).face,\n } as never,\n CleanseSessionAction as never,\n );\n}\n"],"mappings":"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"}
|
package/lib/index.d.mts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/types.ts","../src/index.ts"],"mappings":";;;;;;UAYiB;EACf;EACA,WAAW;;EAEX;;EAEA;;EAEA;EACA,SAAS;;;UAIM;EACf;EACA,WAAW;;;UAII;EACf;EACA,WAAW;EACX;EACA,SAAS;;;UAIM;EACf;EACA,WAAW;EACX;;;UAIe;EACf;EACA,WAAW;EACX;EACA,iBAAiB;;;KAIP,yBACR,gBACA,kBACA,iBACA,kBACA;;UAGa;EACf,WAAW;;EAEX;;;;;;EAMA;;;UAOe;EACf;EACA;EACA;EACA;EACA;EACA;EACA;;;UAIe;EACf;EACA;EACA;EACA;;;;;YCpBU;IACR,eAAe;;;;UAMF;WACN,SAAS;EAClB,SAAS,SAAS;;UAGH;WACN,OAAO;EAChB,WAAW;;UAGI;EACf,IAAI,WAAW,YAAY;EAC3B,OAAO;IACL,YAAY;IACZ,gBAAgB;IAChB;MACE;MACA,gBAAgB;MAChB;MACA;;IAEF;MAAiB;MAAkB;MAAe;;MAChD,QAAQ;;EAEZ,OAAO;IACL,iBAAiB;IACjB;MAAiB;MAAkB;MAAe;;MAChD,QAAQ;;;UAKJ;EACR;EACA;;EAEA;;EAEA;EACA,OAAO;EACP,YAAY;;iBAGL,YAAY,iBAAiB,iBAAiB;iBAsE9C,iBAAiB,gBAAgB,eAAe;iBAqChD,eAAe,gBAAgB,eAAe;;;;;;cA0S1C,sBAAsB;SAC1B;EAEP,YAAY,KAAK;;EAQjB,iBACE,IAAI,WACJ,gBACA,2BACA,SAAS,cACR,QAAQ;;EAKX,KACE,UAAU,WACV,gBACA,iBAAiB,WACjB;IAAS;IAAc;KACvB,SAAS,cACR,QAAQ;;EAaX,OAAO,IAAI,WAAW,oBAAoB,SAAS,cAAW,uDAAA;;;;;;;EAU9D,eAAe,WAAW,WAAW,SAAS,cAAc;IAAU;;;EAQtE,SAAS,WAAW,WAAW,SAAS,cAAc,QAAQ;;EAK9D,KAAK,WAAW,eAAe,SAAS,cAAc,QAAQ;;EAK9D,OAAO,WAAW,iBAAiB,SAAS,cAAc,QAAQ;;EAKlE,MAAM,WAAW,gBAAgB,SAAS,cAAc,QAAQ;;EAK1D,iBACJ,WAAW,WACX,SAAS,cACR,QAAQ;;EAML,eAAe,WAAW,WAAW,SAAS,cAAc,QAAQ;;UAM5D;;UAoFA;;;;;;;;;UA2BA;;UAgCA;;UA4CN;EACR;EACA;EACA,GAAG,eAAe,WAAW,OAAO;EACpC,GAAG,cAAc;EACjB,GAAG,gBAAgB,WAAW;;UAGtB;EACR,UAAU,gBAAgB,UAAU;EACpC,IAAI;;UAGI;EACR,SAAS;IACP;IACA;IACA,UAAU,SAAS,iBAAiB,UAAU,4BAA4B;;;;YAKlE;;IAER,WAAW"}
|
package/lib/index.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["SESSION_BRANCH_VERSION_SCHEMA"],"sources":["../src/shared.ts","../src/index.ts"],"sourcesContent":["/**\n * Host 与 client 共享的类型与常量:HTTP 路由、操作判别联合、Timeline 响应。\n *\n * @module @morlay/ui-conversation-message-actions/shared\n */\n\nimport type { SessionId } from \"@deepseek-ai/dsh-session\";\nimport type { BranchTimeline, CascadePolicy } from \"@morlay/session-branch\";\nimport type { VersionOperation } from \"@morlay/session-branch\";\n\n/** 同源 HTTP 端点(host 注册、client fetch)。 */\nexport const SESSION_EDITOR_PATH = \"/session-editor\";\n\nexport type { VersionOperation } from \"@morlay/session-branch\";\n\n/** 编辑一个已落定文本块并从其轮次边界分支。 */\nexport interface EditOperation {\n action: \"edit\";\n sessionId: SessionId;\n eventSeq: number;\n blockIndex: number;\n text: string;\n cascade: CascadePolicy;\n}\n\n/** 重生成最后一条已落定助手回复。 */\nexport interface RerollOperation {\n action: \"reroll\";\n sessionId: SessionId;\n}\n\n/** 重试任意历史回合。 */\nexport interface RetryOperation {\n action: \"retry\";\n sessionId: SessionId;\n turn: number;\n cascade: CascadePolicy;\n}\n\n/** 截断式回退:原会话回退到闭合边界。 */\nexport interface RewindOperation {\n action: \"rewind\";\n sessionId: SessionId;\n toBoundary: number;\n}\n\n/** 派生式分支:从闭合边界派生新会话。 */\nexport interface ForkOperation {\n action: \"fork\";\n sessionId: SessionId;\n atSeq?: number;\n childSessionId?: SessionId;\n}\n\n/** 清洗一个会话的 surface/provenance 坐标为稠密空间(修复历史加载失败)。 */\nexport interface CleanseOperation {\n action: \"cleanse\";\n sessionId: SessionId;\n}\n\n/** HTTP 接受的判别联合。 */\nexport type SessionEditorOperation =\n | EditOperation\n | RerollOperation\n | RetryOperation\n | RewindOperation\n | ForkOperation\n | CleanseOperation;\n\n/** 操作响应(分支式返回新版本 id;rewind 返回原 id)。 */\nexport interface SessionEditorOperationResult {\n sessionId: SessionId;\n queuedTurns: number;\n /** 操作后会话是否仍有 live owner(客户端据此决定是否重载页面)。 */\n live?: boolean;\n /** cleanse 操作实际重写的事件数。 */\n changed?: number;\n}\n\n/** 可编辑文本块(编辑面枚举)。 */\nexport interface EditableMessageBlock {\n key: string;\n turn: number;\n eventSeq: number;\n blockIndex: number;\n kind: \"user\" | \"assistant.reasoning\" | \"assistant.response\";\n text: string;\n time: number;\n}\n\n/** 可重试回合(重试面枚举)。 */\nexport interface RetryableTurn {\n turn: number;\n userEventSeq: number;\n preview: string;\n time: number;\n}\n\n/** 版本摘要(Timeline 节点投影,值级)。 */\nexport interface VersionSummary {\n sessionId: string;\n parentSessionId?: string;\n effectId?: string;\n inverseSessionId?: string;\n createdAt: number;\n depth: number;\n current: boolean;\n onCurrentEffectPath: boolean;\n operation?: VersionOperation;\n cascade?: CascadePolicy;\n targetTurn?: number;\n blockKind?: EditableMessageBlock[\"kind\"];\n before?: string;\n after?: string;\n}\n\n/** GET /session-editor 的完整投影(Timeline + 编辑/重试面)。 */\nexport interface SessionEditorTimeline {\n sessionId: string;\n messages: EditableMessageBlock[];\n retryableTurns: RetryableTurn[];\n versions: VersionSummary[];\n /** 原子逆链(从当前版本向外,应用顺序)。 */\n undoStack: string[];\n /** 可直接重施加的子版本。 */\n redoSessionIds: string[];\n}\n\n/** 把 {@link BranchTimeline} 投影成 client 用的 {@link SessionEditorTimeline}。 */\nexport function toTimelinePayload(\n sessionId: SessionId,\n timeline: BranchTimeline,\n messages: EditableMessageBlock[],\n retryableTurns: RetryableTurn[],\n): SessionEditorTimeline {\n const currentPath = new Set<string>();\n for (const node of timeline.nodes) currentPath.add(String(node.sessionId));\n const versions: VersionSummary[] = timeline.nodes.map((node) => ({\n sessionId: String(node.sessionId),\n ...(node.parentSessionId === undefined\n ? {}\n : { parentSessionId: String(node.parentSessionId) }),\n ...(node.effect === undefined\n ? {}\n : {\n effectId: node.effect.id,\n inverseSessionId: String(node.inverseSessionId),\n operation: node.effect.operation,\n cascade: node.effect.cascade,\n targetTurn: node.effect.targetTurn,\n ...(node.effect.blockKind === undefined ? {} : { blockKind: node.effect.blockKind }),\n ...(node.effect.before === undefined ? {} : { before: node.effect.before }),\n ...(node.effect.after === undefined ? {} : { after: node.effect.after }),\n }),\n createdAt: node.createdAt,\n depth: depthOf(timeline, node.sessionId),\n current: String(node.sessionId) === String(sessionId),\n onCurrentEffectPath: currentPath.has(String(node.sessionId)),\n }));\n const versionsById = new Map(versions.map((version) => [version.sessionId, version]));\n const undoStack: string[] = [];\n let cursor = versionsById.get(String(sessionId));\n while (cursor?.inverseSessionId !== undefined) {\n if (undoStack.includes(cursor.inverseSessionId)) break;\n undoStack.push(cursor.inverseSessionId);\n cursor = versionsById.get(cursor.inverseSessionId);\n }\n const redoSessionIds = versions\n .filter((version) => version.inverseSessionId === String(sessionId))\n .map((version) => version.sessionId);\n return {\n sessionId: String(sessionId),\n messages,\n retryableTurns,\n versions,\n undoStack,\n redoSessionIds,\n };\n}\n\n/** 计算节点到根的深度。 */\nfunction depthOf(\n timeline: BranchTimeline,\n sessionId: import(\"@deepseek-ai/dsh-session\").SessionId,\n): number {\n const byId = new Map(timeline.nodes.map((node) => [String(node.sessionId), node]));\n let depth = 0;\n let cursor = byId.get(String(sessionId));\n const seen = new Set<string>();\n while (cursor?.parentSessionId !== undefined && !seen.has(String(cursor.sessionId))) {\n seen.add(String(cursor.sessionId));\n depth += 1;\n cursor = byId.get(String(cursor.parentSessionId));\n }\n return depth;\n}\n","/**\n * 编排层 `SessionEditor`:在 `@morlay/session-branch` 的 provider 抽象之上\n * 组装 rewind / retry / fork 的**完整功能**(参考 `dsh-message-edit` 的\n * 产品语义:edit / reroll / retry + 级联策略 + 版本树)。\n *\n * 分层边界:\n * - 数据层(forkFrom / rewind / readBranchPrefix)由 `ctx.sessionBranch`\n * (provider 实现,如 `@morlay/session-rdb`)提供;\n * - 本服务只做**编排**:闭合轮次扫描、版本效果事件构造、派生 seed 组装、\n * rewind 命令透传、版本树投影;\n * - agent 驱动(重放用户输入 / 创建子 agent)是**可选增强**:`agents`\n * 服务以 duck-typed 接口使用(不硬依赖 `@deepseek-ai/dsh-agent`),\n * 缺失时退化为「创建持久化版本」——版本已 durable,之后可随时 resume。\n *\n * @module @morlay/ui-conversation-message-actions\n */\n\nimport { Service, type Context } from \"@deepseek-ai/cordis\";\nimport type { AssistantMessage, ContentBlock, UserMessage } from \"@deepseek-ai/dsh-llm\";\nimport type {\n Session,\n SessionEvent,\n SessionId,\n SurfaceEventType,\n SurfaceIntent,\n} from \"@deepseek-ai/dsh-session\";\nimport { randomUUID } from \"node:crypto\";\nimport {\n SESSION_BRANCH_VERSION_SCHEMA,\n SessionBranchError,\n balanceRewindPrefix,\n type BranchBoundary,\n type BranchTimeline,\n type EditableBlockKind,\n type SessionBranchEffect,\n type SessionBranchVersionEvent,\n} from \"@morlay/session-branch\";\nimport type {\n EditOperation,\n EditableMessageBlock,\n RerollOperation,\n RetryOperation,\n RetryableTurn,\n SessionEditorResult,\n} from \"./types.ts\";\nimport {\n SESSION_EDITOR_PATH,\n type SessionEditorOperation,\n type SessionEditorOperationResult,\n type SessionEditorTimeline,\n toTimelinePayload,\n} from \"./shared.ts\";\n\nexport type { CascadePolicy, EditableBlockKind } from \"@morlay/session-branch\";\nexport type {\n EditableMessageBlock,\n EditOperation,\n RerollOperation,\n RetryOperation,\n RetryableTurn,\n RewindOperation,\n SessionEditorOperation,\n SessionEditorResult,\n} from \"./types.ts\";\n\n/** 闭合轮次折叠(纯函数,供编辑面枚举与测试)。 */\nexport { closedTurns, editableMessages, retryableTurns };\nexport { SESSION_BRANCH_VERSION_SCHEMA } from \"@morlay/session-branch\";\n\n/** 版本树投影别名(透传 `@morlay/session-branch`)。 */\nexport type { BranchTimeline, SessionBranchVersionEvent } from \"@morlay/session-branch\";\n\ndeclare module \"@deepseek-ai/cordis\" {\n interface Context {\n sessionEditor: SessionEditor;\n }\n}\n\n/** —— agent 驱动的 duck-typed 接口(不硬依赖 @deepseek-ai/dsh-agent) —— */\n\nexport interface EditorAgent {\n readonly session: Session;\n followup(message: UserMessage): void;\n}\n\nexport interface EditorAgentHandle {\n readonly agent: EditorAgent;\n dispose(): Promise<void>;\n}\n\nexport interface EditorAgentRegistry {\n get(sessionId: SessionId): EditorAgent | undefined;\n create(options: {\n sessionId?: SessionId;\n seed?: readonly SessionEvent[];\n meta?: {\n cwd?: string;\n parentSession?: SessionId;\n seedLength?: number;\n agentPreset?: string;\n };\n agentOptions?: { provider: string; model: string; maxTokens?: number };\n }): Promise<EditorAgentHandle>;\n /** 从已持久化会话恢复 agent(`AgentRegistry.resume`;create 对已持久化会话失败)。 */\n resume(options: {\n resumeSessionId: SessionId;\n agentOptions?: { provider: string; model: string; maxTokens?: number };\n }): Promise<EditorAgentHandle>;\n}\n\n/** —— 闭合轮次扫描(纯函数) —— */\n\ninterface ClosedTurn {\n turn: number;\n startSeq: number;\n /** 闭合轮次的 `turn/end` seq;未闭合轮次为 undefined。 */\n endSeq?: number;\n /** 是否已闭合(有 `turn/end`)。未闭合轮次的 user 消息仍可编辑。 */\n closed: boolean;\n user?: SessionEvent<\"user/message\">;\n assistants: SessionEvent<\"assistant/message\">[];\n}\n\nfunction closedTurns(events: readonly SessionEvent[]): ClosedTurn[] {\n const result: ClosedTurn[] = [];\n let current: Omit<ClosedTurn, \"endSeq\" | \"closed\"> | undefined;\n for (const event of events) {\n if (event.type === \"turn/start\") {\n current = { turn: event.data.turn, startSeq: event.seq, assistants: [] };\n continue;\n }\n if (current === undefined) continue;\n if (\n event.type === \"user/message\" &&\n current.user === undefined &&\n event.data.source.kind === \"user\"\n ) {\n current.user = event;\n continue;\n }\n if (event.type === \"assistant/message\" && event.data.turn === current.turn) {\n current.assistants.push(event);\n continue;\n }\n if (event.type === \"turn/end\" && event.data.turn === current.turn) {\n result.push({ ...current, endSeq: event.seq, closed: true });\n current = undefined;\n }\n }\n // 未闭合轮次(log 尾部没有 turn/end)也保留:其 user 消息已 append 落定,\n // 编辑时 rewind 到该消息(exclusive drop)重放即可。\n if (current !== undefined) result.push({ ...current, closed: false });\n return result;\n}\n\nfunction isTextualBlock(\n block: ContentBlock | undefined,\n): block is Extract<ContentBlock, { type: \"text\" | \"reasoning\" }> {\n return block?.type === \"text\" || block?.type === \"reasoning\";\n}\n\nfunction userText(message: UserMessage): string {\n return message.content\n .filter((block): block is Extract<ContentBlock, { type: \"text\" }> => block.type === \"text\")\n .map((block) => block.text)\n .join(\"\\n\");\n}\n\nfunction cloneUser(\n message: UserMessage,\n content: ContentBlock[] = structuredClone(message.content),\n): UserMessage {\n return Object.freeze({\n id: randomUUID(),\n role: \"user\",\n content: Object.freeze(content),\n source: Object.freeze({ kind: \"user\" }),\n }) as UserMessage;\n}\n\nfunction replaceTextBlock(\n content: readonly ContentBlock[],\n blockIndex: number,\n text: string,\n): ContentBlock[] {\n const block = content[blockIndex];\n if (!isTextualBlock(block))\n throw new SessionBranchError(\"所选内容块不是可编辑文本。\", \"INVALID_BOUNDARY\");\n return content.map((candidate, index) =>\n index === blockIndex ? ({ ...candidate, text } as ContentBlock) : structuredClone(candidate),\n );\n}\n\nfunction editableMessages(turns: readonly ClosedTurn[]): EditableMessageBlock[] {\n const result: EditableMessageBlock[] = [];\n for (const turn of turns) {\n if (turn.user !== undefined) {\n for (const [blockIndex, block] of turn.user.data.content.entries()) {\n if (block.type !== \"text\") continue;\n result.push({\n key: `${String(turn.user.seq)}:${String(blockIndex)}`,\n turn: turn.turn,\n eventSeq: turn.user.seq,\n blockIndex,\n kind: \"user\",\n text: block.text,\n time: turn.user.time,\n });\n }\n }\n // 未闭合轮次的助手消息是流式 partial,不可编辑(服务端拒绝)。\n if (!turn.closed) continue;\n for (const event of turn.assistants) {\n for (const [blockIndex, block] of event.data.message.content.entries()) {\n if (!isTextualBlock(block)) continue;\n result.push({\n key: `${String(event.seq)}:${String(blockIndex)}`,\n turn: turn.turn,\n eventSeq: event.seq,\n blockIndex,\n kind: block.type === \"reasoning\" ? \"assistant.reasoning\" : \"assistant.response\",\n text: block.text,\n time: event.time,\n });\n }\n }\n }\n return result;\n}\n\nfunction retryableTurns(turns: readonly ClosedTurn[]): RetryableTurn[] {\n return turns.flatMap((turn): RetryableTurn[] =>\n // 未闭合轮次不可重试(无已落定回复可重生成;UI 的 retry 按钮也要求\n // turn 已闭合)。\n turn.user === undefined || !turn.closed\n ? []\n : [\n {\n turn: turn.turn,\n userEventSeq: turn.user.seq,\n preview: userText(turn.user.data),\n time: turn.user.time,\n },\n ],\n );\n}\n\nfunction downstreamUsers(turns: readonly ClosedTurn[], start: number): UserMessage[] {\n return turns\n .slice(start)\n .flatMap((turn): UserMessage[] => (turn.user === undefined ? [] : [cloneUser(turn.user.data)]));\n}\n\nfunction assistantReplacement(\n event: SessionEvent<\"assistant/message\">,\n blockIndex: number,\n text: string,\n): AssistantMessage {\n const replaced = replaceTextBlock(event.data.message.content, blockIndex, text).filter(\n (block) => block.type === \"text\" || block.type === \"reasoning\",\n );\n return Object.freeze({\n id: randomUUID(),\n role: \"assistant\",\n content: Object.freeze(replaced),\n source: Object.freeze({\n kind: \"model\",\n provider: event.data.message.source.provider,\n model: event.data.message.source.model,\n }),\n }) as AssistantMessage;\n}\n\n/** —— 版本效果与派生计划 —— */\n\ninterface OperationPlan {\n /** 目标轮 startSeq(`before` 锚定用;派生点 = 该轮之前最后一个 turn/end)。 */\n anchorSeq: number;\n /**\n * 未闭合轮次 user 编辑:rewind 边界 = 该 user 消息 seq(exclusive——drop\n * 该消息及其后,由编辑版重放替换)。闭合轮次编辑不设置(boundary 走\n * 前一轮 turn/end 的 inclusive 语义)。\n */\n rewindBoundary?: number;\n version: SessionBranchVersionEvent;\n /** 助手块编辑:以编辑后内容构造的完整手工闭合回合。 */\n manualTurn?: { turn: number; user: UserMessage; assistant: AssistantMessage };\n /** 排队重放的用户输入(truncate = 目标轮输入;preserve = 目标轮起全部)。 */\n queuedUsers: UserMessage[];\n}\n\nfunction pairVersionEffect(\n sourceSessionId: SessionId,\n effect: Omit<SessionBranchEffect, \"id\">,\n): SessionBranchVersionEvent {\n return {\n schemaVersion: SESSION_BRANCH_VERSION_SCHEMA,\n effect: { ...effect, id: randomUUID() },\n inverse: { kind: \"restore-version\", sessionId: sourceSessionId },\n };\n}\n\nfunction editPlan(operation: EditOperation, turns: readonly ClosedTurn[]): OperationPlan {\n const turnIndex = turns.findIndex(\n (turn) =>\n operation.eventSeq > turn.startSeq &&\n (turn.endSeq === undefined || operation.eventSeq < turn.endSeq),\n );\n const turn = turns[turnIndex];\n if (turn === undefined)\n throw new SessionBranchError(\"所选消息不属于已落定回合。\", \"INVALID_BOUNDARY\");\n const event =\n turn.user?.seq === operation.eventSeq\n ? turn.user\n : turn.assistants.find((candidate) => candidate.seq === operation.eventSeq);\n if (event === undefined)\n throw new SessionBranchError(\"所选消息不存在或不可编辑。\", \"INVALID_BOUNDARY\");\n\n if (event.type === \"user/message\") {\n const before = event.data.content[operation.blockIndex];\n if (before?.type !== \"text\")\n throw new SessionBranchError(\"所选用户消息块不是文本。\", \"INVALID_BOUNDARY\");\n const edited = cloneUser(\n event.data,\n replaceTextBlock(event.data.content, operation.blockIndex, operation.text),\n );\n const later = operation.cascade === \"preserve\" ? downstreamUsers(turns, turnIndex + 1) : [];\n return {\n anchorSeq: turn.startSeq,\n // 未闭合轮次:rewind 到该 user 消息(exclusive drop 该消息及其后),\n // 由编辑版重放替换;闭合轮次走前一轮 turn/end 的 inclusive 语义。\n ...(turn.closed ? {} : { rewindBoundary: event.seq }),\n version: pairVersionEffect(operation.sessionId, {\n operation: \"edit\",\n cascade: operation.cascade,\n targetTurn: turn.turn,\n targetEventSeq: event.seq,\n targetBlockIndex: operation.blockIndex,\n blockKind: \"user\",\n before: before.text,\n after: operation.text,\n }),\n queuedUsers: [edited, ...later],\n };\n }\n\n // 未闭合轮次的助手消息是流式 partial,没有最终内容可编辑。\n if (!turn.closed)\n throw new SessionBranchError(\"未闭合轮次的助手消息不可编辑。\", \"INVALID_BOUNDARY\");\n const before = event.data.message.content[operation.blockIndex];\n if (!isTextualBlock(before))\n throw new SessionBranchError(\"所选助手消息块不是文本或思考。\", \"INVALID_BOUNDARY\");\n const blockKind: EditableBlockKind =\n before.type === \"reasoning\" ? \"assistant.reasoning\" : \"assistant.response\";\n if (turn.user === undefined)\n throw new SessionBranchError(\"所选助手消息没有可重建的用户输入。\", \"INVALID_BOUNDARY\");\n return {\n anchorSeq: turn.startSeq,\n version: pairVersionEffect(operation.sessionId, {\n operation: \"edit\",\n cascade: operation.cascade,\n targetTurn: turn.turn,\n targetEventSeq: event.seq,\n targetBlockIndex: operation.blockIndex,\n blockKind,\n before: before.text,\n after: operation.text,\n }),\n manualTurn: {\n turn: turn.turn,\n user: cloneUser(turn.user.data),\n assistant: assistantReplacement(event, operation.blockIndex, operation.text),\n },\n queuedUsers: operation.cascade === \"preserve\" ? downstreamUsers(turns, turnIndex + 1) : [],\n };\n}\n\nfunction retryPlan(operation: RetryOperation, turns: readonly ClosedTurn[]): OperationPlan {\n const turnIndex = turns.findIndex((turn) => turn.turn === operation.turn);\n const turn = turns[turnIndex];\n if (turn?.user === undefined)\n throw new SessionBranchError(\"所选回合没有可重放的用户输入。\", \"INVALID_BOUNDARY\");\n return {\n anchorSeq: turn.startSeq,\n version: pairVersionEffect(operation.sessionId, {\n operation: \"retry\",\n cascade: operation.cascade,\n targetTurn: turn.turn,\n targetEventSeq: turn.user.seq,\n }),\n queuedUsers:\n operation.cascade === \"preserve\"\n ? downstreamUsers(turns, turnIndex)\n : [cloneUser(turn.user.data)],\n };\n}\n\nfunction rerollPlan(operation: RerollOperation, turns: readonly ClosedTurn[]): OperationPlan {\n for (let index = turns.length - 1; index >= 0; index -= 1) {\n const turn = turns[index];\n // 未闭合轮次没有已落定的助手回复可重生成。\n if (turn?.user === undefined || !turn.closed) continue;\n const target = turn.assistants.findLast((event) =>\n event.data.message.content.some(isTextualBlock),\n );\n if (target === undefined) continue;\n return {\n anchorSeq: turn.startSeq,\n version: pairVersionEffect(operation.sessionId, {\n operation: \"reroll\",\n cascade: \"truncate\",\n targetTurn: turn.turn,\n targetEventSeq: target.seq,\n }),\n queuedUsers: [cloneUser(turn.user.data)],\n };\n }\n throw new SessionBranchError(\"当前会话没有可重生成的已落定助手回复。\", \"INVALID_BOUNDARY\");\n}\n\n/** —— 种子事件构造(本地纯事件构造器;Session 构造时统一验证) —— */\n\nfunction appendLogSeedEvent(\n events: SessionEvent[],\n type: string,\n data: unknown,\n ignorable = false,\n): void {\n events.push({\n type: type as SessionEvent[\"type\"],\n seq: events.length,\n time: Date.now(),\n data: data as SessionEvent[\"data\"],\n ...(ignorable ? { ignorable: true as const } : {}),\n } as SessionEvent);\n}\n\nfunction appendSurfaceSeedEvent<T extends SurfaceEventType>(\n events: SessionEvent[],\n type: T,\n data: import(\"@deepseek-ai/dsh-session\").SessionEvent<T>[\"data\"],\n intent: SurfaceIntent,\n): void {\n events.push({\n type,\n seq: events.length,\n time: Date.now(),\n data,\n surfaceOp: intent.surfaceOp,\n ...(intent.sourceEventSeqs === undefined ? {} : { sourceEventSeqs: intent.sourceEventSeqs }),\n } as SessionEvent<T>);\n}\n\nfunction appendManualTurn(\n events: SessionEvent[],\n manual: { turn: number; user: UserMessage; assistant: AssistantMessage },\n): void {\n const { turn, user, assistant } = manual;\n appendLogSeedEvent(events, \"turn/start\", { turn });\n appendSurfaceSeedEvent(events, \"user/message\", user, { surfaceOp: \"append\" });\n appendLogSeedEvent(events, \"step/start\", { turn, step: 1 });\n appendSurfaceSeedEvent(\n events,\n \"assistant/message\",\n { turn, step: 1, message: assistant },\n {\n surfaceOp: \"append\",\n sourceEventSeqs: [],\n },\n );\n appendLogSeedEvent(events, \"step/end\", { turn, step: 1 });\n appendLogSeedEvent(events, \"turn/end\", { turn, reason: { kind: \"completed\" } });\n}\n\n/**\n * 把派生 seed 后缀落地到 **live** 会话。上游 `Session.append` 不保留\n * `ignorable` 标记(只保留 type/data/surface 元数据),而版本效果事件必须\n * 保持 ignorable(live log 保留、不落 canonical log),因此:\n * - ignorable 事件(版本效果)直接 push 内存 log(不发布 `session/event`;\n * 服务端语义事件,客户端无需感知;surfaceManager 对非 surface 事件 fold\n * 无副作用);\n * - 其余事件(手工回合 manualTurn)走 `append`(surface 校验 + 发布)。\n * 后续统一由 write-behind flush 落盘(RDB 稠密化时过滤 ignorable)。\n */\nfunction appendSeedSuffixLive(session: Session, seedSuffix: readonly SessionEvent[]): void {\n for (const event of seedSuffix) {\n if (event.ignorable === true) {\n const s = session as unknown as {\n log: SessionEvent[];\n eventsSnapshot?: unknown;\n };\n // 版本效果:ignorable 语义(live log 保留、不落 canonical log)。\n // session.append 不保留 ignorable 标记,因此直接 push 内存 log(不发布\n // session/event;服务端语义事件,客户端无需感知;surfaceManager 对非\n // surface 事件 fold 无副作用)。seq 按 log 续接重编号(seedSuffix 内部\n // 编号从 0 起,与截断后 live log 不对齐)。\n s.log.push({ ...event, seq: s.log.length } as SessionEvent);\n s.eventsSnapshot = undefined;\n continue;\n }\n const s = session as unknown as {\n append(\n type: string,\n data: unknown,\n opts?: { surfaceOp?: unknown; sourceEventSeqs?: readonly number[] },\n ): SessionEvent;\n };\n const raw = event as SessionEvent & {\n surfaceOp?: unknown;\n sourceEventSeqs?: readonly number[];\n };\n if (raw.surfaceOp !== undefined) {\n s.append(event.type, event.data, {\n surfaceOp: raw.surfaceOp,\n ...(raw.sourceEventSeqs === undefined ? {} : { sourceEventSeqs: raw.sourceEventSeqs }),\n });\n } else {\n s.append(event.type, event.data);\n }\n }\n}\n\n/** —— 编排服务 —— */\n\n/**\n * `ctx.sessionEditor`:rewind / retry / fork 的完整功能编排。\n * 组合 `ctx.sessionBranch`(provider 抽象)与可选的 `agents` 服务。\n */\nexport class SessionEditor extends Service {\n static inject = [\"sessionBranch\", \"sessionPersistence\", \"sessions\"];\n\n constructor(ctx: Context) {\n super(ctx, \"sessionEditor\");\n // HTTP 路由随类构造注册(dsh 用 default 类插件,apply 函数不被调用)。\n // bundles 顺序保证 webserver(ctx.n)先于本类实例化。\n registerHttpRoutes(ctx);\n }\n\n /** 定位 `atSeq` 锚定的闭合边界(透传 provider)。 */\n readBranchPrefix(\n id: SessionId,\n atSeq?: number,\n mode?: \"after\" | \"before\",\n signal?: AbortSignal,\n ): Promise<BranchBoundary> {\n return this.ctx.sessionBranch.readBranchPrefix(id, atSeq, mode, signal);\n }\n\n /** 从持久化源派生新会话(透传 provider;不驱动 agent)。 */\n fork(\n sourceId: SessionId,\n atSeq?: number,\n childSessionId?: SessionId,\n meta?: { cwd?: string; agentPreset?: string },\n signal?: AbortSignal,\n ): Promise<SessionId> {\n return this.ctx.sessionBranch.forkFrom(\n sourceId,\n {\n ...(atSeq === undefined ? {} : { atSeq }),\n ...(childSessionId === undefined ? {} : { childSessionId }),\n ...(meta === undefined ? {} : { meta }),\n },\n signal,\n );\n }\n\n /** 截断式回退:原会话回退到闭合边界(透传 provider)。 */\n rewind(id: SessionId, toBoundary: number, signal?: AbortSignal) {\n return this.ctx.sessionBranch.rewind(id, toBoundary, signal);\n }\n\n /**\n * 清洗一个会话的 surface/provenance 坐标为稠密空间(透传 sessionBranch)。\n * 历史加载失败(坐标混叠导致 seed 校验失败)时调用,清洗后重新加载即可。\n * `cleanseSession` 是 rdb 实现层新增的服务面(契约层 `SessionBranch`\n * 没有此方法),经运行时访问。\n */\n cleanseSession(sessionId: SessionId, signal?: AbortSignal): Promise<{ changed: number }> {\n const branch = this.ctx.sessionBranch as unknown as {\n cleanseSession(id: SessionId, signal?: AbortSignal): Promise<{ changed: number }>;\n };\n return branch.cleanseSession(sessionId, signal);\n }\n\n /** 完整版本树投影(透传 provider 组合)。 */\n timeline(sessionId: SessionId, signal?: AbortSignal): Promise<BranchTimeline> {\n return this.ctx.sessionBranch.timeline(sessionId, signal);\n }\n\n /** 编辑一个已落定文本块并从其轮次边界分支。 */\n edit(operation: EditOperation, signal?: AbortSignal): Promise<SessionEditorResult> {\n return this.branchOperation(operation, signal);\n }\n\n /** 重生成最后一条已落定助手回复。 */\n reroll(operation: RerollOperation, signal?: AbortSignal): Promise<SessionEditorResult> {\n return this.branchOperation(operation, signal);\n }\n\n /** 重试任意历史回合。 */\n retry(operation: RetryOperation, signal?: AbortSignal): Promise<SessionEditorResult> {\n return this.branchOperation(operation, signal);\n }\n\n /** 可编辑消息块枚举(Timeline 编辑面)。 */\n async editableMessages(\n sessionId: SessionId,\n signal?: AbortSignal,\n ): Promise<EditableMessageBlock[]> {\n const events = await this.readEvents(sessionId, signal);\n return editableMessages(closedTurns(events));\n }\n\n /** 可重试回合枚举(Timeline 重试面)。 */\n async retryableTurns(sessionId: SessionId, signal?: AbortSignal): Promise<RetryableTurn[]> {\n const events = await this.readEvents(sessionId, signal);\n return retryableTurns(closedTurns(events));\n }\n\n /** 执行一个分支式操作(edit / reroll / retry)。 */\n private async branchOperation(\n operation: EditOperation | RerollOperation | RetryOperation,\n signal?: AbortSignal,\n ): Promise<SessionEditorResult> {\n signal?.throwIfAborted();\n const events = await this.readEvents(operation.sessionId, signal);\n const turns = closedTurns(events);\n const plan =\n operation.action === \"edit\"\n ? editPlan(operation, turns)\n : operation.action === \"retry\"\n ? retryPlan(operation, turns)\n : rerollPlan(operation, turns);\n // rewind 前解析模型配置:就地编辑可能截断掉最后的 request/header\n // (编辑第一轮 boundary = -1 会清空全部),重放 agent 需要 provider/model。\n const headerConfig = events.findLast((event) => event.type === \"request/header\")?.data.header\n .config;\n\n // 派生 seed 后缀:版本效果 + 可选手工回合。版本事件对核心是 ignorable\n // (上游不认识;branch 层后端特判保留),保证非 branch 读者可安全跳过。\n const seedSuffix: SessionEvent[] = [];\n appendLogSeedEvent(seedSuffix, \"session-branch/version\", plan.version, true);\n if (plan.manualTurn !== undefined) appendManualTurn(seedSuffix, plan.manualTurn);\n\n // 就地编辑:不创建新会话、不改变 session id。先 rewind 截断原会话到\n // 目标轮之前的闭合边界(抛弃后续事件),再把版本效果与重放输入\n // append 回同一会话,最后(可选)驱动 agent 重放排队输入。\n // 未闭合轮次 user 编辑:rewind 边界 = 该 user 消息 seq(exclusive drop\n // 该消息及其后,由编辑版重放替换);闭合轮次编辑走前一轮 turn/end 的\n // inclusive 语义。\n const turnIndex = turns.findIndex((turn) => turn.startSeq === plan.anchorSeq);\n const boundary =\n plan.rewindBoundary !== undefined\n ? plan.rewindBoundary\n : turnIndex <= 0\n ? -1\n : turns[turnIndex - 1]!.endSeq!;\n const live = this.ctx.sessions.get(operation.sessionId);\n await this.ctx.sessionBranch.rewind(operation.sessionId, boundary, signal);\n if (seedSuffix.length > 0) {\n if (live !== undefined) {\n // live:落地内存 log(版本效果 ignorable 保留、manualTurn 走 append),\n // 同步 coordinator cursor 后显式 flush(版本效果 push 不发布、不进\n // 缓冲,cursor 会落后 log——不 sync 则 manualTurn 的 seq 校验错位)。\n appendSeedSuffixLive(live, seedSuffix);\n this.ctx.sessionBranch.syncLiveCursor(operation.sessionId);\n await this.ctx.sessions.flush(live);\n } else {\n // rewind 后保留的事件数:turn/end inclusive = boundary + 1;\n // user/message exclusive = boundary(该消息被 drop,由编辑版替换)。\n // 与 rdb rewind 一致地平衡化:exclusive 截断可能残留未配对的\n // step/start(真实 agent-loop 的 step/start 在 user/message 之前),\n // 续写 seq 必须从平衡后的保留前缀续接,否则落盘 log 对 token meter\n // 重放非法(孤儿 step/start 使后续 step/start 报错)。\n const rawKeepLength = boundary + (plan.rewindBoundary === undefined ? 1 : 0);\n const keepLength = balanceRewindPrefix(events.slice(0, rawKeepLength)).length;\n const renumbered = seedSuffix.map(\n (event, index) =>\n ({\n ...event,\n seq: keepLength + index,\n }) as SessionEvent,\n );\n await this.ctx.sessionPersistence.append(operation.sessionId, renumbered);\n }\n }\n\n // 可选增强:agent 驱动(重放排队用户输入)。缺失 agents 服务时退化为\n // 已 durable 的就地版本——可随时继续输入。\n const queuedTurns = await this.driveAgent(\n operation.sessionId,\n plan.queuedUsers,\n signal,\n headerConfig,\n );\n return {\n sessionId: operation.sessionId,\n queuedTurns,\n // live 标记:操作后是否仍有 live owner(driveAgent 可能 resume 出 agent)。\n live: this.ctx.sessions.get(operation.sessionId) !== undefined,\n };\n }\n\n /** 读取会话事件:live 优先,否则走持久化原始读取(不含合成 closers)。 */\n private async readEvents(\n sessionId: SessionId,\n signal?: AbortSignal,\n ): Promise<readonly SessionEvent[]> {\n const live = this.ctx.sessions.get(sessionId);\n if (live !== undefined) return live.events;\n // cold:读原始事件(`loadStored`,scanRows 只做 torn-tail 切割、不补\n // closers)。`inspect` 会经 coordinator 的 `prepareCore` 给未闭合 log\n // 补合成 step/end + turn/end——未闭合轮次被掩盖成闭合,编辑未闭合轮次\n // 的 user 消息会走错边界。\n const branch = this.ctx.sessionBranch as unknown as {\n readRawEvents(\n id: SessionId,\n signal?: AbortSignal,\n ): Promise<{ meta: unknown; events: readonly SessionEvent[] }>;\n };\n return (await branch.readRawEvents(sessionId, signal)).events;\n }\n\n /**\n * 可选 agent 驱动:优先复用现有 live agent(用户会话驻留——rewind 已截断\n * 其 session 内存,followup 会基于截断后历史重放),否则 `resume` 已持久化\n * 会话。模型配置来自 branchOperation 在 rewind 前解析的 `headerConfig`\n * (rewind 可能截断 request/header);缺失时回退到当前 events。无 agents\n * 服务、无可用模型路由或恢复失败时退化为持久化版本(已 durable)。\n * 返回实际排队的输入数。\n */\n private async driveAgent(\n sessionId: SessionId,\n queuedUsers: readonly UserMessage[],\n signal?: AbortSignal,\n headerConfig?: { provider?: string; model?: string; maxTokens?: number },\n ): Promise<number> {\n if (queuedUsers.length === 0) return 0;\n signal?.throwIfAborted();\n const agents = this.ctx.get(\"agents\") as EditorAgentRegistry | undefined;\n if (agents === undefined) return 0;\n const provider = headerConfig?.provider ?? \"\";\n const model = headerConfig?.model ?? \"\";\n if (provider.length === 0 || model.length === 0) {\n // 兜底:从当前会话 events 解析(headerConfig 未由调用方提供时)。\n const events = await this.readEvents(sessionId, signal);\n const config = events.findLast((event) => event.type === \"request/header\")?.data.header\n .config;\n const fallbackProvider = config?.provider ?? \"\";\n const fallbackModel = config?.model ?? \"\";\n if (fallbackProvider.length === 0 || fallbackModel.length === 0) return 0;\n return this.queueThroughAgent(\n sessionId,\n queuedUsers,\n signal,\n fallbackProvider,\n fallbackModel,\n );\n }\n return this.queueThroughAgent(sessionId, queuedUsers, signal, provider, model);\n }\n\n /** 经 live agent(复用)或 resume(重建)排队重放输入;返回排队数。 */\n private async queueThroughAgent(\n sessionId: SessionId,\n queuedUsers: readonly UserMessage[],\n signal: AbortSignal | undefined,\n provider: string,\n model: string,\n ): Promise<number> {\n const agents = this.ctx.get(\"agents\") as EditorAgentRegistry | undefined;\n if (agents === undefined) return 0;\n // 现有 live agent(用户会话驻留):直接排队输入——就地编辑后其 session\n // 内存已被 rewind 截断,followup 基于截断后历史重放,不改 id、不重建。\n const existing = agents.get(sessionId);\n if (existing !== undefined) {\n for (const message of queuedUsers) existing.followup(message);\n await this.ctx.sessions.flush(existing.session);\n return queuedUsers.length;\n }\n // cold:resume 已持久化会话(create 会因「已存在持久化日志」失败)。\n // resume 后 agent 驻留(与用户发消息后的正常状态一致),不 dispose——\n // dispose 会把 session 从 store 移除,破坏客户端打开的窗口。\n const handle = await agents\n .resume({ resumeSessionId: sessionId, agentOptions: { provider, model } })\n .catch((error: unknown) => {\n // agent 组合失败不应使已 durable 的版本失效:退化为持久化版本。\n this.ctx.logger.warn(\n \"session-editor: agent resume failed (%s); version remains durable\",\n String(error),\n );\n return undefined;\n });\n if (handle === undefined) return 0;\n for (const message of queuedUsers) handle.agent.followup(message);\n await this.ctx.sessions.flush(handle.agent.session);\n return queuedUsers.length;\n }\n}\n\nexport default SessionEditor;\n\n// ---------------------------------------------------------------------------\n// HTTP 面(host):GET /session-editor(timeline 投影)/ POST /session-editor\n// (edit | reroll | retry | rewind | fork)。参考 dsh-message-edit 的同源端点。\n// ---------------------------------------------------------------------------\n\ninterface HttpRequestLike {\n method?: string;\n url?: string;\n on(event: \"data\", listener: (chunk: Uint8Array | string) => void): this;\n on(event: \"end\", listener: () => void): this;\n on(event: \"error\", listener: (error: unknown) => void): this;\n}\n\ninterface HttpResponseLike {\n writeHead(status: number, headers?: Record<string, string>): unknown;\n end(body?: string): void;\n}\n\ninterface HttpServerLike {\n register(route: {\n kind: \"exact\";\n path: string;\n handler: (request: HttpRequestLike, response: HttpResponseLike) => void | Promise<void>;\n }): () => void;\n}\n\ndeclare module \"@deepseek-ai/cordis\" {\n interface Context {\n /** dsh web 的 HTTP route carrier(@deepseek-ai/dsh-host-webserver,`WebRoute` 协议)。 */\n webServer: HttpServerLike;\n }\n}\n\nfunction objectValue(value: unknown): Record<string, unknown> {\n if (typeof value !== \"object\" || value === null || Array.isArray(value)) {\n throw new TypeError(\"请求体必须是 JSON 对象。\");\n }\n return value as Record<string, unknown>;\n}\n\nfunction sessionIdOf(value: unknown): SessionId {\n if (typeof value !== \"string\" || value.length === 0)\n throw new TypeError(\"sessionId 必须是非空字符串。\");\n return value as SessionId;\n}\n\nfunction integerOf(value: unknown, name: string): number {\n if (!Number.isSafeInteger(value) || (value as number) < 0) {\n throw new TypeError(`${name} 必须是非负安全整数。`);\n }\n return value as number;\n}\n\nfunction cascadeOf(value: unknown): import(\"@morlay/session-branch\").CascadePolicy {\n if (value !== \"truncate\" && value !== \"preserve\")\n throw new TypeError(\"cascade 必须是 truncate 或 preserve。\");\n return value;\n}\n\nfunction decodeOperation(value: unknown): SessionEditorOperation {\n const record = objectValue(value);\n const sessionId = sessionIdOf(record[\"sessionId\"]);\n switch (record[\"action\"]) {\n case \"edit\":\n if (typeof record[\"text\"] !== \"string\") throw new TypeError(\"text 必须是字符串。\");\n return {\n action: \"edit\",\n sessionId,\n eventSeq: integerOf(record[\"eventSeq\"], \"eventSeq\"),\n blockIndex: integerOf(record[\"blockIndex\"], \"blockIndex\"),\n text: record[\"text\"],\n cascade: cascadeOf(record[\"cascade\"]),\n };\n case \"reroll\":\n return { action: \"reroll\", sessionId };\n case \"retry\":\n return {\n action: \"retry\",\n sessionId,\n turn: integerOf(record[\"turn\"], \"turn\"),\n cascade: cascadeOf(record[\"cascade\"]),\n };\n case \"rewind\":\n return {\n action: \"rewind\",\n sessionId,\n toBoundary: integerOf(record[\"toBoundary\"], \"toBoundary\"),\n };\n case \"fork\":\n return {\n action: \"fork\",\n sessionId,\n ...(record[\"atSeq\"] === undefined ? {} : { atSeq: integerOf(record[\"atSeq\"], \"atSeq\") }),\n ...(record[\"childSessionId\"] === undefined\n ? {}\n : { childSessionId: sessionIdOf(record[\"childSessionId\"]) }),\n };\n case \"cleanse\":\n return { action: \"cleanse\", sessionId };\n default:\n throw new TypeError(\"action 必须是 edit、reroll、retry、rewind、fork 或 cleanse。\");\n }\n}\n\nfunction requestJson(request: HttpRequestLike): Promise<unknown> {\n return new Promise((resolve, reject) => {\n const decoder = new TextDecoder();\n let text = \"\";\n request.on(\"data\", (chunk) => {\n text += typeof chunk === \"string\" ? chunk : decoder.decode(chunk, { stream: true });\n });\n request.on(\"end\", () => {\n try {\n text += decoder.decode();\n resolve(JSON.parse(text) as unknown);\n } catch (error) {\n reject(error);\n }\n });\n request.on(\"error\", reject);\n });\n}\n\nfunction respondJson(response: HttpResponseLike, status: number, value: unknown): void {\n response.writeHead(status, {\n \"content-type\": \"application/json; charset=utf-8\",\n \"cache-control\": \"no-store\",\n });\n response.end(JSON.stringify(value));\n}\n\n/** GET 投影:timeline + 编辑/重试面。 */\nasync function readTimeline(\n editor: SessionEditor,\n sessionId: SessionId,\n): Promise<SessionEditorTimeline> {\n const timeline = await editor.timeline(sessionId);\n const messages = await editor.editableMessages(sessionId);\n const retryable = await editor.retryableTurns(sessionId);\n return toTimelinePayload(sessionId, timeline, messages, retryable);\n}\n\nasync function runOperation(\n editor: SessionEditor,\n operation: SessionEditorOperation,\n): Promise<SessionEditorOperationResult> {\n switch (operation.action) {\n case \"edit\": {\n const result = await editor.edit(operation);\n return {\n sessionId: result.sessionId,\n queuedTurns: result.queuedTurns,\n ...(result.live === undefined ? {} : { live: result.live }),\n };\n }\n case \"reroll\": {\n const result = await editor.reroll(operation);\n return {\n sessionId: result.sessionId,\n queuedTurns: result.queuedTurns,\n ...(result.live === undefined ? {} : { live: result.live }),\n };\n }\n case \"retry\": {\n const result = await editor.retry(operation);\n return {\n sessionId: result.sessionId,\n queuedTurns: result.queuedTurns,\n ...(result.live === undefined ? {} : { live: result.live }),\n };\n }\n case \"rewind\":\n await editor.rewind(operation.sessionId, operation.toBoundary);\n return { sessionId: operation.sessionId, queuedTurns: 0 };\n case \"fork\":\n return {\n sessionId: await editor.fork(\n operation.sessionId,\n operation.atSeq,\n operation.childSessionId,\n ),\n queuedTurns: 0,\n };\n case \"cleanse\": {\n const { changed } = await editor.cleanseSession(operation.sessionId);\n return { sessionId: operation.sessionId, queuedTurns: 0, changed };\n }\n }\n}\n\nasync function handleRoute(\n editor: SessionEditor,\n request: HttpRequestLike,\n response: HttpResponseLike,\n): Promise<void> {\n try {\n if (request.method === \"GET\") {\n const url = new URL(request.url ?? SESSION_EDITOR_PATH, \"http://session-editor.local\");\n const sessionId = sessionIdOf(url.searchParams.get(\"sessionId\"));\n respondJson(response, 200, await readTimeline(editor, sessionId));\n return;\n }\n if (request.method === \"POST\") {\n respondJson(\n response,\n 200,\n await runOperation(editor, decodeOperation(await requestJson(request))),\n );\n return;\n }\n response.writeHead(405);\n response.end();\n } catch (error: unknown) {\n const message = error instanceof Error ? error.message : String(error);\n respondJson(response, error instanceof TypeError ? 400 : 409, { error: message });\n }\n}\n\n/** 注册同源 HTTP 路由(`ctx.webServer` 由 dsh web 的 webserver 包提供;缺失时跳过)。 */\nfunction registerHttpRoutes(ctx: Context): void {\n const webServer = ctx.get(\"webServer\") as HttpServerLike | undefined;\n if (webServer === undefined) return;\n ctx.effect(() => {\n const editor = ctx.sessionEditor;\n return webServer.register({\n kind: \"exact\",\n path: SESSION_EDITOR_PATH,\n handler: (request, response) => handleRoute(editor, request, response),\n });\n }, \"session-editor: HTTP route\");\n}\n"],"mappings":"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"}
|
package/lib/invariant.d.mts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { Context } from "@deepseek-ai/cordis";
|
|
2
|
-
//#region src/invariant.d.ts
|
|
3
|
-
/** Cordis companion plugin name. */
|
|
4
|
-
declare const name = "ui-conversation-message-actions-invariant";
|
|
5
|
-
/** Service required before the companion can reserve package ownership. */
|
|
6
|
-
declare const inject: string[];
|
|
7
|
-
/**
|
|
8
|
-
* Register this package's invariant companion.
|
|
9
|
-
* @param ctx - Cordis context carrying the invariant service.
|
|
10
|
-
* @returns the installed registration's disposer after setup succeeds.
|
|
11
|
-
*/
|
|
12
|
-
declare const apply: (ctx: Context) => Promise<() => void>;
|
|
13
|
-
//#endregion
|
|
14
|
-
export { apply, inject, name };
|
|
15
|
-
//# sourceMappingURL=invariant.d.mts.map
|
package/lib/invariant.d.mts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"invariant.d.mts","names":[],"sources":["../src/invariant.ts"],"mappings":";;;cAWa;;cAEA;;;;;;cAcA,QAAK,KAAS,YAAU"}
|
package/lib/invariant.mjs
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
//#region src/invariant.ts
|
|
2
|
-
const PACKAGE_NAME = "@morlay/ui-conversation-message-actions";
|
|
3
|
-
/** Cordis companion plugin name. */
|
|
4
|
-
const name = "ui-conversation-message-actions-invariant";
|
|
5
|
-
/** Service required before the companion can reserve package ownership. */
|
|
6
|
-
const inject = ["invariants"];
|
|
7
|
-
/**
|
|
8
|
-
* No runtime invariant: orchestration correctness (in-place rewind/retry,
|
|
9
|
-
* version-effect ignorable semantics) is covered by editor contract tests;
|
|
10
|
-
* this package exposes no continuously observable in-process relation.
|
|
11
|
-
*/
|
|
12
|
-
const install = () => {};
|
|
13
|
-
/**
|
|
14
|
-
* Register this package's invariant companion.
|
|
15
|
-
* @param ctx - Cordis context carrying the invariant service.
|
|
16
|
-
* @returns the installed registration's disposer after setup succeeds.
|
|
17
|
-
*/
|
|
18
|
-
const apply = (ctx) => Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));
|
|
19
|
-
//#endregion
|
|
20
|
-
export { apply, inject, name };
|
|
21
|
-
|
|
22
|
-
//# sourceMappingURL=invariant.mjs.map
|
package/lib/invariant.mjs.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"invariant.mjs","names":[],"sources":["../src/invariant.ts"],"sourcesContent":["/**\n * Package-owned invariant companion for `@morlay/ui-conversation-message-actions`.\n * @module @morlay/ui-conversation-message-actions/invariant\n */\n\nimport type { Context } from \"@deepseek-ai/cordis\";\nimport type { InvariantInstaller } from \"@deepseek-ai/dsh-invariants\";\n\nconst PACKAGE_NAME = \"@morlay/ui-conversation-message-actions\";\n\n/** Cordis companion plugin name. */\nexport const name = \"ui-conversation-message-actions-invariant\";\n/** Service required before the companion can reserve package ownership. */\nexport const inject = [\"invariants\"];\n\n/**\n * No runtime invariant: orchestration correctness (in-place rewind/retry,\n * version-effect ignorable semantics) is covered by editor contract tests;\n * this package exposes no continuously observable in-process relation.\n */\nconst install: InvariantInstaller = () => {};\n\n/**\n * Register this package's invariant companion.\n * @param ctx - Cordis context carrying the invariant service.\n * @returns the installed registration's disposer after setup succeeds.\n */\nexport const apply = (ctx: Context): Promise<() => void> =>\n Promise.resolve(ctx.invariants.register(PACKAGE_NAME, install));\n"],"mappings":";AAQA,MAAM,eAAe;;AAGrB,MAAa,OAAO;;AAEpB,MAAa,SAAS,CAAC,YAAY;;;;;;AAOnC,MAAM,gBAAoC,CAAC;;;;;;AAO3C,MAAa,SAAS,QACpB,QAAQ,QAAQ,IAAI,WAAW,SAAS,cAAc,OAAO,CAAC"}
|