langchain_agentx_stream_ui 0.6.4 → 0.7.0

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.
Files changed (37) hide show
  1. package/dist/{AskUserQuestionToolBody-J8MqSUEs.d.ts → AskUserQuestionToolBody-C6J742a2.d.ts} +2 -2
  2. package/dist/{MarkdownBlock-DeICJUtu.d.ts → MarkdownBlock-B_wNhCB4.d.ts} +1 -1
  3. package/dist/{chunk-GBY5DJ7L.js → chunk-4RIOBLGB.js} +1 -1
  4. package/dist/chunk-4RIOBLGB.js.map +1 -0
  5. package/dist/{chunk-YHCK76OU.js → chunk-7TBPTIAP.js} +78 -37
  6. package/dist/chunk-7TBPTIAP.js.map +1 -0
  7. package/dist/{chunk-6Z4ZF36Z.js → chunk-DP7V33X7.js} +1 -1
  8. package/dist/chunk-DP7V33X7.js.map +1 -0
  9. package/dist/{chunk-O5GERXTY.js → chunk-EFJMU4WW.js} +213 -23
  10. package/dist/chunk-EFJMU4WW.js.map +1 -0
  11. package/dist/{chunk-GYFC2DI7.js → chunk-GLUQUP3A.js} +218 -5
  12. package/dist/chunk-GLUQUP3A.js.map +1 -0
  13. package/dist/{chunk-5XELRP3S.js → chunk-OV6UUIA3.js} +4 -4
  14. package/dist/chunk-OV6UUIA3.js.map +1 -0
  15. package/dist/default.css +16 -0
  16. package/dist/index.d.ts +36 -14
  17. package/dist/index.js +221 -18
  18. package/dist/index.js.map +1 -1
  19. package/dist/{multi-session-4GMo1sLl.d.ts → multi-session-DhTXvNpi.d.ts} +22 -3
  20. package/dist/multi-session.d.ts +4 -4
  21. package/dist/multi-session.js +6 -6
  22. package/dist/{nodes-7_0rCAc4.d.ts → nodes-MpVB9C5d.d.ts} +7 -1
  23. package/dist/{sessionViewOptions-EIBugOkf.d.ts → sessionViewOptions-DeTrGjRM.d.ts} +1 -1
  24. package/dist/tools-presentation.d.ts +3 -3
  25. package/dist/tools-presentation.js +2 -2
  26. package/dist/tools.d.ts +5 -5
  27. package/dist/tools.js +4 -4
  28. package/dist/{types-DAkw2VOv.d.ts → types-SVtInovH.d.ts} +1 -1
  29. package/dist/virtual.d.ts +1 -1
  30. package/dist/virtual.js +3 -3
  31. package/package.json +1 -1
  32. package/dist/chunk-5XELRP3S.js.map +0 -1
  33. package/dist/chunk-6Z4ZF36Z.js.map +0 -1
  34. package/dist/chunk-GBY5DJ7L.js.map +0 -1
  35. package/dist/chunk-GYFC2DI7.js.map +0 -1
  36. package/dist/chunk-O5GERXTY.js.map +0 -1
  37. package/dist/chunk-YHCK76OU.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { b as ToolDisplayProps, T as ToolBodyComponent } from './types-DAkw2VOv.js';
3
- import { T as ToolDisplayRegistry } from './sessionViewOptions-EIBugOkf.js';
2
+ import { b as ToolDisplayProps, T as ToolBodyComponent } from './types-SVtInovH.js';
3
+ import { T as ToolDisplayRegistry } from './sessionViewOptions-DeTrGjRM.js';
4
4
 
5
5
  declare function DefaultToolBody({ result, bodyMode, onBodyModeChange, }: ToolDisplayProps): react_jsx_runtime.JSX.Element;
6
6
 
@@ -1,5 +1,5 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
- import { a as ToolBodyMode } from './types-DAkw2VOv.js';
2
+ import { a as ToolBodyMode } from './types-SVtInovH.js';
3
3
 
4
4
  declare const MAX_PREVIEW_LINES = 3;
5
5
  interface TruncatedContentProps {
@@ -663,4 +663,4 @@ export {
663
663
  MarkdownRendererContext,
664
664
  MarkdownBlock
665
665
  };
666
- //# sourceMappingURL=chunk-GBY5DJ7L.js.map
666
+ //# sourceMappingURL=chunk-4RIOBLGB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/view/tools/presentation/paths.ts","../src/view/tools/presentation/searchHelpers.ts","../src/view/tools/presentation/TruncatedContent.tsx","../src/view/tools/presentation/bashHelpers.ts","../src/view/tools/presentation/BodyBlockList.tsx","../src/view/tools/presentation/diffHelpers.ts","../src/view/tools/presentation/DiffView.tsx","../src/view/tools/presentation/MarkdownBlock.tsx","../src/core/context/MarkdownRendererContext.tsx"],"sourcesContent":["/**\n * paths.ts — 路径展示 helper\n *\n * 职责:\n * 将绝对路径转为较短展示字符串(Web 无 cwd 时仅 normalize 分隔符)。\n *\n * 链路位置:\n * T1+ Read/Edit Widget title。\n *\n * 当前裁剪范围:\n * 不做 relpath(浏览器无 process.cwd);仅 slash 归一化。\n *\n * 对齐参考:\n * CLI widgets/tools/helpers.py display_path\n */\n\nexport function displayPath(filePath: string): string {\n if (!filePath) return '';\n return filePath.replace(/\\\\/g, '/');\n}\n","/**\n * searchHelpers.ts — grep/glob 标题与列表正文 helper\n *\n * 对齐参考:CLI widgets/tools/helpers.py format_pattern_title、format_search_result_body\n */\n\nimport { displayPath } from './paths';\n\nexport const SEARCH_LIST_PREVIEW_LINES = 20;\n\nconst FOUND_SUMMARY_RE = /^(Found .+|No files found|No matches found)/i;\n\nexport function formatPatternTitle(pattern: string, path?: string | null): string {\n const parts = [`pattern: \"${pattern}\"`];\n if (path) {\n parts.push(`path: \"${displayPath(path)}\"`);\n }\n return parts.join(', ');\n}\n\nexport function extractSearchSummary(output: string): string {\n const text = output.trim();\n if (!text) return '';\n const match = text.match(FOUND_SUMMARY_RE);\n if (match) return match[1].trim();\n const first = text.split('\\n', 1)[0]?.trim() ?? '';\n if (/^(found |no files|no matches)/i.test(first)) return first;\n return '';\n}\n\nexport function truncateLines(\n text: string,\n maxLines: number,\n): { text: string; truncated: boolean } {\n const lines = text.split('\\n');\n if (lines.length <= maxLines) {\n return { text, truncated: false };\n }\n return {\n text: lines.slice(0, maxLines).join('\\n'),\n truncated: true,\n };\n}\n\nexport function formatSearchResultBody(\n output: string,\n maxListLines = SEARCH_LIST_PREVIEW_LINES,\n): string {\n const text = output.trim();\n if (!text) return '(No output)';\n\n const summary = extractSearchSummary(text);\n const lines = text.split('\\n');\n let listLines: string[];\n\n if (summary && lines[0]?.trim() === summary) {\n listLines = lines.slice(1);\n } else if (summary) {\n listLines = lines.filter((ln) => ln.trim() !== summary);\n } else {\n listLines = lines;\n }\n\n const listText = listLines\n .map((ln) => ln.trim())\n .filter(Boolean)\n .join('\\n');\n\n if (listText) {\n const { text: truncated, truncated: wasTruncated } = truncateLines(\n listText,\n maxListLines,\n );\n const suffix = wasTruncated ? `\\n… 列表超过 ${maxListLines} 行,已截断` : '';\n if (summary) return `${summary}\\n${truncated}${suffix}`;\n return `${truncated}${suffix}`;\n }\n\n return summary || text.slice(0, 500);\n}\n","/**\n * TruncatedContent.tsx — PREVIEW 行数截断\n *\n * 职责:\n * 默认 3 行预览 + expand 控件;FULL 模式展示全文。\n *\n * 链路位置:\n * DefaultToolBody、T1+ 各 ToolBody 正文。\n *\n * 当前裁剪范围:\n * 纯文本;不做 ANSI / 终端 wrap。\n *\n * 对齐参考:\n * CLI presentation/shell_output.py · CC utils/terminal.ts MAX_LINES_TO_SHOW=3\n */\nimport type { ToolBodyMode } from '../types';\n\nexport const MAX_PREVIEW_LINES = 3;\n\nexport interface TruncatedContentProps {\n text: string;\n mode: ToolBodyMode;\n maxLines?: number;\n onExpand?: () => void;\n}\n\nexport function TruncatedContent({\n text,\n mode,\n maxLines = MAX_PREVIEW_LINES,\n onExpand,\n}: TruncatedContentProps) {\n const lines = text.split('\\n');\n const needsTruncate = mode === 'preview' && lines.length > maxLines;\n\n if (!needsTruncate) {\n return (\n <div className=\"lax-tool-body__block\" data-variant=\"normal\">\n <pre className=\"lax-tool-body__text\">{text}</pre>\n </div>\n );\n }\n\n const preview = lines.slice(0, maxLines).join('\\n');\n const remaining = lines.length - maxLines;\n\n return (\n <div className=\"lax-tool-body__block\" data-variant=\"normal\">\n <pre className=\"lax-tool-body__text\">{preview}</pre>\n <button\n type=\"button\"\n className=\"lax-tool-body__expand\"\n onClick={onExpand}\n >\n +{remaining} lines (点击展开)\n </button>\n </div>\n );\n}\n","/**\n * bashHelpers.ts — bash 命令与输出解析\n *\n * 对齐参考:CLI widgets/tools/helpers.py · bash/widget.py format_body_blocks\n */\nimport type { ToolBodyMode } from '../types';\nimport { MAX_PREVIEW_LINES } from './TruncatedContent';\nimport type { BodyBlock } from './BodyBlockList';\n\nexport const MAX_COMMAND_DISPLAY_CHARS = 160;\nexport const MAX_COMMAND_DISPLAY_LINES = 2;\n\nconst CWD_RESET_PATTERN = /(?:^|\\n)(Shell cwd was reset to .+)$/m;\nconst EXIT_CODE_PATTERN = /(?:^|\\n)Exit code:\\s*(\\d+)/m;\n\nexport function truncateCommand(command: string, maxChars = MAX_COMMAND_DISPLAY_CHARS): string {\n let text = command.trim();\n if (!text) return '';\n const lines = text.split('\\n');\n if (lines.length > MAX_COMMAND_DISPLAY_LINES) {\n text = lines.slice(0, MAX_COMMAND_DISPLAY_LINES).join('\\n');\n }\n if (text.length > maxChars) {\n text = `${text.slice(0, maxChars)}…`;\n }\n return text;\n}\n\nexport function formatBashTitle(input: unknown): string {\n const inp =\n input != null && typeof input === 'object' && !Array.isArray(input)\n ? (input as Record<string, unknown>)\n : {};\n const command = String(inp.command ?? '').trim();\n if (!command) return 'Bash';\n return `Bash(${truncateCommand(command)})`;\n}\n\nexport function splitBashStreams(output: string): {\n stdout: string;\n stderr: string;\n cwdWarning: string | null;\n} {\n let text = output ?? '';\n let cwdWarning: string | null = null;\n const cwdMatch = text.match(CWD_RESET_PATTERN);\n if (cwdMatch) {\n cwdWarning = cwdMatch[1]?.trim() ?? null;\n text = text.replace(CWD_RESET_PATTERN, '').trim();\n }\n\n let stdout = text;\n let stderr = '';\n if (text.includes('\\n--- stderr ---\\n')) {\n const parts = text.split('\\n--- stderr ---\\n');\n stdout = parts[0] ?? '';\n stderr = parts[1] ?? '';\n } else if (text.startsWith('stderr:')) {\n stderr = text.slice(7).trim();\n stdout = '';\n }\n\n return { stdout: stdout.trim(), stderr: stderr.trim(), cwdWarning };\n}\n\nexport function parseExitCode(output: string, fallback?: number | null): number | null {\n const match = (output ?? '').match(EXIT_CODE_PATTERN);\n if (match) return Number.parseInt(match[1], 10);\n return fallback ?? null;\n}\n\nexport function formatDuration(seconds: number): string {\n if (seconds < 1) return `${seconds.toFixed(1)}s`;\n if (seconds < 60) return `${Math.floor(seconds)}s`;\n if (seconds < 3600) {\n const minutes = Math.floor(seconds / 60);\n const secs = Math.floor(seconds % 60);\n return secs === 0 ? `${minutes}m` : `${minutes}m ${secs}s`;\n }\n const hours = Math.floor(seconds / 3600);\n const minutes = Math.floor((seconds % 3600) / 60);\n return minutes === 0 ? `${hours}h` : `${hours}h ${minutes}m`;\n}\n\nexport function formatTimeoutFooter(timeoutMs: number | null | undefined): string | null {\n if (!timeoutMs) return null;\n return `(timeout ${formatDuration(timeoutMs / 1000)})`;\n}\n\nfunction previewStreamText(text: string, mode: ToolBodyMode): string {\n if (mode === 'full' || !text.trim()) return text;\n const lines = text.split('\\n');\n if (lines.length <= MAX_PREVIEW_LINES) return text;\n // 对齐 CLI ShellOutputPreviewer:PREVIEW 只保留前 N 行;expand hint 由 UI 层单独渲染\n return lines.slice(0, MAX_PREVIEW_LINES).join('\\n');\n}\n\nfunction resolveStreams(\n display: Record<string, unknown> | null,\n summary: string,\n): { stdout: string; stderr: string; cwdWarning: string | null } {\n if (display && ('stdout' in display || 'stderr' in display)) {\n return {\n stdout: String(display.stdout ?? ''),\n stderr: String(display.stderr ?? ''),\n cwdWarning: null,\n };\n }\n return splitBashStreams(summary);\n}\n\nfunction resolveExitCode(\n display: Record<string, unknown> | null,\n summary: string,\n): number | null {\n if (display && 'exit_code' in display) {\n const code = display.exit_code;\n if (typeof code === 'number') return code;\n if (typeof code === 'string' && code.trim()) {\n const n = Number.parseInt(code, 10);\n if (Number.isFinite(n)) return n;\n }\n return null;\n }\n return parseExitCode(summary);\n}\n\nfunction resolveTimeoutMs(\n display: Record<string, unknown> | null,\n meta: unknown,\n): number | null {\n if (display?.timeout_ms != null) {\n const n = Number(display.timeout_ms);\n return Number.isFinite(n) ? n : null;\n }\n if (meta != null && typeof meta === 'object' && !Array.isArray(meta)) {\n const ms = (meta as Record<string, unknown>).timeout_ms;\n if (ms != null) {\n const n = Number(ms);\n return Number.isFinite(n) ? n : null;\n }\n }\n return null;\n}\n\nexport function buildBashBodyBlocks(\n display: unknown,\n summary: string,\n meta: unknown,\n mode: ToolBodyMode,\n isError: boolean,\n): { blocks: BodyBlock[]; truncated: boolean; remainingLines: number } {\n const d =\n display != null && typeof display === 'object' && !Array.isArray(display)\n ? (display as Record<string, unknown>)\n : null;\n\n if (isError) {\n const blocks: BodyBlock[] = [\n { text: summary.trim() || 'Error', variant: 'error' },\n ];\n const footer = formatTimeoutFooter(resolveTimeoutMs(d, meta));\n if (footer) blocks.push({ text: footer, variant: 'dim' });\n return { blocks, truncated: false, remainingLines: 0 };\n }\n\n const { stdout, stderr, cwdWarning } = resolveStreams(d, summary);\n const code = resolveExitCode(d, summary);\n const blocks: BodyBlock[] = [];\n let truncated = false;\n let remainingLines = 0;\n\n const addStream = (text: string, variant: BodyBlock['variant']) => {\n if (!text.trim()) return;\n const lines = text.split('\\n');\n const rendered = previewStreamText(text, mode);\n if (mode === 'preview' && lines.length > MAX_PREVIEW_LINES) {\n truncated = true;\n remainingLines += lines.length - MAX_PREVIEW_LINES;\n }\n blocks.push({ text: rendered, variant });\n };\n\n addStream(stdout, 'normal');\n addStream(stderr, 'error');\n\n if (cwdWarning) {\n blocks.push({ text: cwdWarning, variant: 'dim' });\n }\n\n if (code != null && code !== 0) {\n blocks.push({ text: `Exit code: ${code}`, variant: 'error' });\n }\n\n if (blocks.length === 0) {\n const noOutputExpected = Boolean(d?.no_output_expected);\n blocks.push({\n text: noOutputExpected ? 'Done' : '(No output)',\n variant: 'dim',\n });\n }\n\n const footer = formatTimeoutFooter(resolveTimeoutMs(d, meta));\n if (footer) {\n blocks.push({ text: footer, variant: 'dim' });\n }\n\n if (d?.truncated && d?.overflow_file) {\n blocks.push({\n text: `Output truncated; see ${String(d.overflow_file)}`,\n variant: 'dim',\n });\n }\n\n return { blocks, truncated, remainingLines };\n}\n","/**\n * BodyBlockList.tsx — ⎿ 多块正文布局\n *\n * 职责:\n * 多块平面文本,支持 normal / error / dim 变体。\n *\n * 链路位置:\n * T3 bash stdout/stderr 分块;DefaultToolBody 可复用。\n *\n * 当前裁剪范围:\n * 块内不做 TruncatedContent(由调用方传入已截断文本)。\n *\n * 对齐参考:\n * CLI presentation/message_layout.py · CC MessageResponse.tsx ⎿ 前缀\n */\n\nexport interface BodyBlock {\n text: string;\n variant?: 'normal' | 'error' | 'dim';\n}\n\nexport interface BodyBlockListProps {\n blocks: BodyBlock[];\n}\n\nexport function BodyBlockList({ blocks }: BodyBlockListProps) {\n if (blocks.length === 0) return null;\n\n return (\n <div className=\"lax-tool-body__blocks\">\n {blocks.map((block, index) => (\n <div\n key={index}\n className=\"lax-tool-body__block\"\n data-variant={block.variant ?? 'normal'}\n >\n <pre className=\"lax-tool-body__text\">{block.text}</pre>\n </div>\n ))}\n </div>\n );\n}\n","/**\n * diffHelpers.ts — unified diff 生成与解析\n *\n * 对齐参考:CLI widgets/tools/helpers.py format_diff_from_strings\n */\n\nexport const WRITE_PREVIEW_LINES = 10;\nexport const DIFF_PREVIEW_LINES = 12;\n\nexport type DiffLineKind = 'add' | 'remove' | 'context' | 'meta';\n\nexport interface ParsedDiffLine {\n kind: DiffLineKind;\n text: string;\n}\n\nexport function countLines(text: string): number {\n if (!text) return 0;\n return text.split('\\n').length;\n}\n\nexport function formatDiffFromStrings(oldText: string, newText: string): string {\n if (oldText === newText) return '(no changes)';\n\n const oldLines = oldText.split('\\n');\n const newLines = newText.split('\\n');\n const body: string[] = [];\n let i = 0;\n let j = 0;\n\n while (i < oldLines.length || j < newLines.length) {\n const oldLine = oldLines[i];\n const newLine = newLines[j];\n\n if (i < oldLines.length && j < newLines.length && oldLine === newLine) {\n body.push(` ${oldLine}`);\n i += 1;\n j += 1;\n continue;\n }\n\n if (i < oldLines.length && (j >= newLines.length || oldLine !== newLine)) {\n body.push(`-${oldLine}`);\n i += 1;\n continue;\n }\n\n if (j < newLines.length) {\n body.push(`+${newLine}`);\n j += 1;\n }\n }\n\n if (body.length === 0) return '(no changes)';\n\n return ['--- old', '+++ new', '@@', ...body].join('\\n');\n}\n\nexport function parseDiffText(diff: string): ParsedDiffLine[] {\n if (diff === '(no changes)') {\n return [{ kind: 'meta', text: diff }];\n }\n\n const result: ParsedDiffLine[] = [];\n for (const line of diff.split('\\n')) {\n if (!line && result.length > 0) {\n result.push({ kind: 'context', text: '' });\n continue;\n }\n if (line.startsWith('+++') || line.startsWith('---') || line.startsWith('@@')) {\n result.push({ kind: 'meta', text: line });\n } else if (line.startsWith('+')) {\n result.push({ kind: 'add', text: line.slice(1) });\n } else if (line.startsWith('-')) {\n result.push({ kind: 'remove', text: line.slice(1) });\n } else if (line.startsWith(' ')) {\n result.push({ kind: 'context', text: line.slice(1) });\n } else {\n result.push({ kind: 'context', text: line });\n }\n }\n return result;\n}\n\nexport function resolveEditDiffText(\n display: unknown,\n input: unknown,\n summary: string,\n): string {\n const d =\n display != null && typeof display === 'object' && !Array.isArray(display)\n ? (display as Record<string, unknown>)\n : null;\n const inp =\n input != null && typeof input === 'object' && !Array.isArray(input)\n ? (input as Record<string, unknown>)\n : {};\n\n const diffField = d?.diff;\n if (typeof diffField === 'string' && diffField.trim()) {\n return diffField.trim();\n }\n\n const oldStr =\n (typeof d?.old_string === 'string' ? d.old_string : '') ||\n (typeof inp.old_string === 'string' ? inp.old_string : '');\n const newStr =\n (typeof d?.new_string === 'string' ? d.new_string : '') ||\n (typeof inp.new_string === 'string' ? inp.new_string : '');\n\n if (oldStr || newStr) {\n return formatDiffFromStrings(oldStr, newStr);\n }\n\n const trimmed = summary.trim();\n if (trimmed) return trimmed;\n return '(done)';\n}\n","/**\n * DiffView.tsx — unified diff 渲染(纯 CSS +/- 行前缀)\n *\n * 对齐参考:CC components/FileEditToolDiff.tsx · CLI format_diff_from_strings\n */\nimport type { ToolBodyMode } from '../types';\nimport {\n DIFF_PREVIEW_LINES,\n parseDiffText,\n type ParsedDiffLine,\n} from './diffHelpers';\n\nexport interface DiffViewProps {\n diff: string;\n mode: ToolBodyMode;\n maxPreviewLines?: number;\n onExpand?: () => void;\n}\n\nfunction renderLine(line: ParsedDiffLine, index: number) {\n const prefix =\n line.kind === 'add' ? '+' : line.kind === 'remove' ? '-' : line.kind === 'meta' ? '' : ' ';\n\n return (\n <div\n key={index}\n className=\"lax-tool-diff__line\"\n data-kind={line.kind}\n >\n {prefix ? (\n <span className=\"lax-tool-diff__prefix\" aria-hidden>\n {prefix}\n </span>\n ) : null}\n <span className=\"lax-tool-diff__text\">{line.text}</span>\n </div>\n );\n}\n\nexport function DiffView({\n diff,\n mode,\n maxPreviewLines = DIFF_PREVIEW_LINES,\n onExpand,\n}: DiffViewProps) {\n const lines = parseDiffText(diff);\n const needsTruncate = mode === 'preview' && lines.length > maxPreviewLines;\n const visible = needsTruncate ? lines.slice(0, maxPreviewLines) : lines;\n\n return (\n <div className=\"lax-tool-diff\">\n {visible.map(renderLine)}\n {needsTruncate ? (\n <button\n type=\"button\"\n className=\"lax-tool-body__expand\"\n onClick={onExpand}\n >\n +{lines.length - maxPreviewLines} diff lines (点击展开)\n </button>\n ) : null}\n </div>\n );\n}\n","/**\n * MarkdownBlock.tsx — 完整 markdown 渲染(带性能优化)\n *\n * 职责:display.type=markdown 等场景的段落/列表/代码块/表格。\n * 链路位置:ReadToolBody 等 ToolBody。\n *\n * 性能优化(参考 CC):\n * - 快速路径:纯文本跳过 markdown 解析\n * - 内容哈希缓存:相同内容不重复解析\n * - 组件记忆化:避免不必要的重渲染\n *\n * 功能:\n * - 完整 GFM 支持 (GitHub Flavored Markdown)\n * - 代码语法高亮\n * - 表格渲染\n * - 拷贝按钮\n */\nimport { memo, useMemo, useState } from 'react';\nimport ReactMarkdown from 'react-markdown';\nimport remarkGfm from 'remark-gfm';\nimport { Prism as SyntaxHighlighter } from 'react-syntax-highlighter';\nimport { oneDark } from 'react-syntax-highlighter/dist/esm/styles/prism';\n\nimport { useMarkdownRenderer } from '../../../core/context/MarkdownRendererContext';\nimport type { ToolBodyMode } from '../types';\nimport { MAX_PREVIEW_LINES } from './TruncatedContent';\n\nexport interface MarkdownBlockProps {\n text: string;\n mode: ToolBodyMode;\n maxLines?: number;\n onExpand?: () => void;\n className?: string;\n}\n\n/**\n * 简单的内容哈希函数(用于缓存)\n * 使用 djb2 算法,性能好且冲突率低\n */\nfunction hashContent(content: string): string {\n let hash = 5381;\n for (let i = 0; i < content.length; i++) {\n hash = ((hash << 5) + hash + content.charCodeAt(i)) & 0xffffffff;\n }\n return hash.toString(36);\n}\n\n/**\n * 检测是否包含 markdown 语法\n * 快速路径:如果没有任何 markdown 标记,直接渲染为纯文本\n * 检查前 500 字符即可(markdown 语法通常在前面)\n */\nfunction hasMarkdownSyntax(content: string): boolean {\n const sample = content.length > 500 ? content.slice(0, 500) : content;\n // 检测常见的 markdown 语法标记\n const MD_SYNTAX_RE = /[#*`|[>\\-_~]|\\n\\n|^\\d+\\. |\\n\\d+\\. /;\n return MD_SYNTAX_RE.test(sample);\n}\n\n// 代码块组件(带拷贝功能)- 记忆化\ninterface CodeBlockProps {\n language: string;\n content: string;\n}\n\nconst CodeBlock = memo(function CodeBlock({ language, content }: CodeBlockProps) {\n const [copied, setCopied] = useState(false);\n\n const handleCopy = async () => {\n try {\n await navigator.clipboard.writeText(content);\n setCopied(true);\n setTimeout(() => setCopied(false), 2000);\n } catch (err) {\n console.error('Failed to copy:', err);\n }\n };\n\n return (\n <div className=\"lax-code-block\">\n <div className=\"lax-code-block__header\">\n <span className=\"lax-code-block__lang\">{language || 'code'}</span>\n <button\n type=\"button\"\n className={`lax-code-block__copy ${copied ? 'lax-code-block__copy--copied' : ''}`}\n onClick={handleCopy}\n title={copied ? '已拷贝!' : '拷贝代码'}\n >\n {copied ? (\n <>\n <svg className=\"lax-code-block__icon\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={3}>\n <path strokeLinecap=\"round\" strokeLinejoin=\"round\" d=\"M5 13l4 4L19 7\" />\n </svg>\n <span>已拷贝</span>\n </>\n ) : (\n <>\n <svg className=\"lax-code-block__icon\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" strokeWidth={2}>\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z\"\n />\n </svg>\n <span>拷贝</span>\n </>\n )}\n </button>\n </div>\n <SyntaxHighlighter\n language={language}\n style={oneDark}\n customStyle={{\n margin: 0,\n padding: 0,\n background: 'transparent',\n }}\n showLineNumbers={false}\n wrapLongLines={true}\n >\n {content}\n </SyntaxHighlighter>\n </div>\n );\n});\n\n// Markdown 组件配置 - 缓存在组件外部,避免重复创建\nconst MARKDOWN_COMPONENTS = {\n // 代码块\n code({ node, className, children, ...props }: any) {\n const match = /language-(\\w+)/.exec(className || '');\n const codeContent = String(children).replace(/\\n$/, '');\n const inline = !className;\n\n if (!inline && match) {\n return <CodeBlock language={match[1]} content={codeContent} />;\n }\n\n return (\n <code className=\"lax-markdown__inline-code\" {...props}>\n {children}\n </code>\n );\n },\n // 标题\n h1({ children }: any) { return <h1 className=\"lax-markdown__heading lax-markdown__h1\">{children}</h1>; },\n h2({ children }: any) { return <h2 className=\"lax-markdown__heading lax-markdown__h2\">{children}</h2>; },\n h3({ children }: any) { return <h3 className=\"lax-markdown__heading lax-markdown__h3\">{children}</h3>; },\n h4({ children }: any) { return <h4 className=\"lax-markdown__heading lax-markdown__h4\">{children}</h4>; },\n h5({ children }: any) { return <h5 className=\"lax-markdown__heading lax-markdown__h5\">{children}</h5>; },\n h6({ children }: any) { return <h6 className=\"lax-markdown__heading lax-markdown__h6\">{children}</h6>; },\n // 段落\n p({ children }: any) { return <p className=\"lax-markdown__paragraph\">{children}</p>; },\n // 列表\n ul({ children }: any) { return <ul className=\"lax-markdown__list lax-markdown__ul\">{children}</ul>; },\n ol({ children }: any) { return <ol className=\"lax-markdown__list lax-markdown__ol\">{children}</ol>; },\n li({ children }: any) { return <li className=\"lax-markdown__li\">{children}</li>; },\n // 链接\n a({ children, href }: any) {\n return (\n <a href={href} className=\"lax-markdown__link\" target=\"_blank\" rel=\"noopener noreferrer\">\n {children}\n </a>\n );\n },\n // 引用\n blockquote({ children }: any) { return <blockquote className=\"lax-markdown__blockquote\">{children}</blockquote>; },\n // 表格\n table({ children }: any) {\n return (\n <div className=\"lax-markdown__table-wrapper\">\n <table className=\"lax-markdown__table\">{children}</table>\n </div>\n );\n },\n thead({ children }: any) { return <thead className=\"lax-markdown__thead\">{children}</thead>; },\n tbody({ children }: any) { return <tbody className=\"lax-markdown__tbody\">{children}</tbody>; },\n tr({ children }: any) { return <tr className=\"lax-markdown__tr\">{children}</tr>; },\n th({ children }: any) { return <th className=\"lax-markdown__th\">{children}</th>; },\n td({ children }: any) { return <td className=\"lax-markdown__td\">{children}</td>; },\n // 分隔线\n hr() { return <hr className=\"lax-markdown__hr\" />; },\n // 强调\n strong({ children }: any) { return <strong className=\"lax-markdown__strong\">{children}</strong>; },\n em({ children }: any) { return <em className=\"lax-markdown__em\">{children}</em>; },\n};\n\n// 纯文本渲染组件(快速路径)\nconst PureTextRenderer = memo(function PureTextRenderer({ content, className }: { content: string; className?: string }) {\n return (\n <div className={['lax-markdown', 'lax-markdown--pure', className].filter(Boolean).join(' ')}>\n <p className=\"lax-markdown__paragraph\">{content}</p>\n </div>\n );\n});\n\n// Markdown 渲染组件(记忆化)\nconst MarkdownRenderer = memo(function MarkdownRenderer({ content, className }: { content: string; className?: string }) {\n return (\n <div className={['lax-markdown', className].filter(Boolean).join(' ')}>\n <ReactMarkdown\n remarkPlugins={[remarkGfm]}\n components={MARKDOWN_COMPONENTS}\n >\n {content}\n </ReactMarkdown>\n </div>\n );\n});\n\nexport function MarkdownBlock({\n text,\n mode,\n maxLines = MAX_PREVIEW_LINES,\n onExpand,\n className,\n}: MarkdownBlockProps) {\n const markdownRenderer = useMarkdownRenderer();\n\n // 使用 useMemo 缓存截断和哈希计算\n const { visible, remaining, needsTruncate, contentHash } = useMemo(() => {\n const lines = text.split('\\n');\n const needsTruncate = mode === 'preview' && lines.length > maxLines;\n const visible = needsTruncate ? lines.slice(0, maxLines).join('\\n') : text;\n const remaining = lines.length - maxLines;\n const contentHash = hashContent(visible);\n return { visible, remaining, needsTruncate, contentHash };\n }, [text, mode, maxLines]);\n\n // 如果应用层提供了 markdownRenderer,使用它\n if (markdownRenderer) {\n return (\n <div className={['lax-markdown', className].filter(Boolean).join(' ')}>\n {markdownRenderer({ content: visible, className: 'lax-markdown__rich' })}\n {needsTruncate ? (\n <button\n type=\"button\"\n className=\"lax-tool-body__expand\"\n onClick={onExpand}\n >\n +{remaining} 行 (点击展开)\n </button>\n ) : null}\n </div>\n );\n }\n\n // 使用内容哈希作为 key 来利用 React 的 diff 算法\n // 相同内容不会重新渲染\n const rendererKey = `md-${contentHash}`;\n\n // 快速路径:纯文本直接渲染,跳过 markdown 解析\n if (!hasMarkdownSyntax(visible)) {\n return (\n <>\n <PureTextRenderer key={rendererKey} content={visible} className={className} />\n {needsTruncate ? (\n <button\n type=\"button\"\n className=\"lax-tool-body__expand\"\n onClick={onExpand}\n >\n +{remaining} 行 (点击展开)\n </button>\n ) : null}\n </>\n );\n }\n\n // 完整 markdown 渲染\n return (\n <>\n <MarkdownRenderer key={rendererKey} content={visible} className={className} />\n {needsTruncate ? (\n <button\n type=\"button\"\n className=\"lax-tool-body__expand\"\n onClick={onExpand}\n >\n +{remaining} 行 (点击展开)\n </button>\n ) : null}\n </>\n );\n}\n","/**\n * MarkdownRendererContext — 富 Markdown 注入(与 ToolDisplayRegistry 解耦,避免循环依赖)\n */\nimport { createContext, useContext, type ReactNode } from 'react';\n\nexport interface MarkdownRendererProps {\n content: string;\n className?: string;\n}\n\nexport type MarkdownRenderer = (props: MarkdownRendererProps) => ReactNode;\n\nexport const MarkdownRendererContext = createContext<MarkdownRenderer | undefined>(\n undefined,\n);\n\nexport function useMarkdownRenderer(): MarkdownRenderer | undefined {\n return useContext(MarkdownRendererContext);\n}\n"],"mappings":"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","names":["minutes","blocks","footer","jsx","jsx","jsxs","jsx","jsxs","CodeBlock","PureTextRenderer","MarkdownRenderer","needsTruncate","visible","remaining","contentHash"]}
@@ -5,7 +5,7 @@ import {
5
5
  getNoopInteractionBus,
6
6
  resolveToolBody,
7
7
  useInteractionBus
8
- } from "./chunk-5XELRP3S.js";
8
+ } from "./chunk-OV6UUIA3.js";
9
9
  import {
10
10
  DEFAULT_SESSION_VIEW_OPTIONS,
11
11
  MultiSessionStoreContext,
@@ -24,13 +24,17 @@ import {
24
24
  useSessionStatus,
25
25
  useSessionViewOptions,
26
26
  useToolDisplayOptions
27
- } from "./chunk-O5GERXTY.js";
27
+ } from "./chunk-EFJMU4WW.js";
28
28
  import {
29
- createDefaultToolRegistry
30
- } from "./chunk-GYFC2DI7.js";
29
+ classifyToolResultSoftKind,
30
+ createDefaultToolRegistry,
31
+ isToolResultCancelled,
32
+ resolveToolCancelDisplayText,
33
+ softKindTestId
34
+ } from "./chunk-GLUQUP3A.js";
31
35
  import {
32
36
  MarkdownRendererContext
33
- } from "./chunk-GBY5DJ7L.js";
37
+ } from "./chunk-4RIOBLGB.js";
34
38
 
35
39
  // src/view/markdown/diagramSmartFit.ts
36
40
  function parseSvgLength(attr) {
@@ -1388,7 +1392,32 @@ function TextBubble({ nodeId }) {
1388
1392
 
1389
1393
  // src/view/nodes/ToolCallNode.tsx
1390
1394
  import { useEffect as useEffect7, useState as useState8 } from "react";
1395
+
1396
+ // src/view/tools/ToolCancelSoftBody.tsx
1391
1397
  import { jsx as jsx12 } from "react/jsx-runtime";
1398
+ function ToolCancelSoftBody({ result }) {
1399
+ const softKind = classifyToolResultSoftKind(result) ?? "rejected";
1400
+ const modifier = softKind === "canceled" ? "canceled" : "rejected";
1401
+ return /* @__PURE__ */ jsx12(
1402
+ "div",
1403
+ {
1404
+ className: `lax-tool-body lax-tool-body--${modifier}`,
1405
+ "data-cancel-ui-kind": softKind,
1406
+ children: /* @__PURE__ */ jsx12(
1407
+ "div",
1408
+ {
1409
+ className: "lax-tool-body__block",
1410
+ "data-variant": "dim",
1411
+ "data-testid": softKindTestId(softKind, "tool"),
1412
+ children: /* @__PURE__ */ jsx12("pre", { className: "lax-tool-body__text", children: resolveToolCancelDisplayText(softKind) })
1413
+ }
1414
+ )
1415
+ }
1416
+ );
1417
+ }
1418
+
1419
+ // src/view/nodes/ToolCallNode.tsx
1420
+ import { jsx as jsx13 } from "react/jsx-runtime";
1392
1421
  function ToolCallCard({ nodeId, layout = "default" }) {
1393
1422
  const node = useNodeTyped(nodeId, "tool_call");
1394
1423
  const { registry, defaultBodyMode } = useToolDisplayOptions();
@@ -1408,7 +1437,8 @@ function ToolCallCard({ nodeId, layout = "default" }) {
1408
1437
  const hasSubagentProgress = (node.subagentProgress?.length ?? 0) > 0;
1409
1438
  const hasSubagentTranscript = (node.subagentTranscript?.length ?? 0) > 0;
1410
1439
  const showBody = hasSubagentProgress || hasSubagentTranscript || !(node.status === "running" && result == null);
1411
- const BodyComponent = resolveToolBody(node.toolName, displayBody, registry);
1440
+ const cancelled = node.status === "cancelled" || isToolResultCancelled(result);
1441
+ const BodyComponent = cancelled ? ToolCancelSoftBody : resolveToolBody(node.toolName, displayBody, registry);
1412
1442
  const title = formatToolTitle(
1413
1443
  node.toolName,
1414
1444
  details?.input ?? node.input,
@@ -1430,44 +1460,55 @@ function ToolCallCard({ nodeId, layout = "default" }) {
1430
1460
  bodyMode,
1431
1461
  onBodyModeChange: setBodyMode
1432
1462
  };
1433
- const errorMessage = result?.error?.message ?? null;
1463
+ const shellStatus = cancelled ? "cancelled" : node.status;
1464
+ const errorMessage = cancelled ? null : result?.error?.message ?? null;
1434
1465
  const permissionWait = viewOptions.permissionUiMode !== "standalone" && node.status === "running" ? pendingPermission : void 0;
1435
- return /* @__PURE__ */ jsx12(
1466
+ return /* @__PURE__ */ jsx13(
1436
1467
  ToolCallShell,
1437
1468
  {
1438
- status: node.status,
1469
+ status: shellStatus,
1439
1470
  title,
1440
1471
  progress: node.progress ?? void 0,
1441
1472
  errorMessage,
1442
1473
  layout,
1443
1474
  permissionWait,
1444
1475
  permissionUiMode: viewOptions.permissionUiMode,
1445
- children: showBody ? /* @__PURE__ */ jsx12("div", { className: "lax-tool-shell__body", children: /* @__PURE__ */ jsx12(BodyComponent, { ...bodyProps }) }) : null
1476
+ children: showBody ? /* @__PURE__ */ jsx13("div", { className: "lax-tool-shell__body", children: /* @__PURE__ */ jsx13(BodyComponent, { ...bodyProps }) }) : null
1446
1477
  }
1447
1478
  );
1448
1479
  }
1449
1480
 
1450
1481
  // src/view/nodes/StepNode.tsx
1451
- import { jsx as jsx13 } from "react/jsx-runtime";
1482
+ import { jsx as jsx14 } from "react/jsx-runtime";
1452
1483
  function StepCard({ nodeId }) {
1453
1484
  const node = useNodeTyped(nodeId, "step");
1454
1485
  if (!node) return null;
1455
- return /* @__PURE__ */ jsx13("details", { className: "lax-step-card", "data-status": node.status, children: /* @__PURE__ */ jsx13("summary", { className: "lax-step-card__summary", children: node.label }) });
1486
+ return /* @__PURE__ */ jsx14("details", { className: "lax-step-card", "data-status": node.status, children: /* @__PURE__ */ jsx14("summary", { className: "lax-step-card__summary", children: node.label }) });
1456
1487
  }
1457
1488
 
1458
1489
  // src/view/nodes/ErrorNode.tsx
1459
- import { jsx as jsx14, jsxs as jsxs11 } from "react/jsx-runtime";
1490
+ import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
1460
1491
  function ErrorCard({ nodeId }) {
1461
1492
  const node = useNodeTyped(nodeId, "error");
1462
1493
  if (!node) return null;
1463
- return /* @__PURE__ */ jsxs11("div", { className: "lax-error-card", role: "alert", children: [
1464
- /* @__PURE__ */ jsx14("div", { className: "lax-error-card__message", children: node.message }),
1465
- node.errorType ? /* @__PURE__ */ jsx14("div", { className: "lax-error-card__type", children: node.errorType }) : null
1466
- ] });
1494
+ const variant = node.variant ?? "error";
1495
+ const isSoft = variant === "interrupt" || variant === "hook_stopped";
1496
+ return /* @__PURE__ */ jsxs11(
1497
+ "div",
1498
+ {
1499
+ className: isSoft ? "lax-error-card lax-error-card--interrupt" : "lax-error-card",
1500
+ role: isSoft ? "status" : "alert",
1501
+ "data-variant": variant,
1502
+ children: [
1503
+ /* @__PURE__ */ jsx15("div", { className: "lax-error-card__message", children: node.message }),
1504
+ node.errorType ? /* @__PURE__ */ jsx15("div", { className: "lax-error-card__type", children: node.errorType }) : null
1505
+ ]
1506
+ }
1507
+ );
1467
1508
  }
1468
1509
 
1469
1510
  // src/view/nodes/UnknownNode.tsx
1470
- import { jsx as jsx15, jsxs as jsxs12 } from "react/jsx-runtime";
1511
+ import { jsx as jsx16, jsxs as jsxs12 } from "react/jsx-runtime";
1471
1512
  function UnknownCard({ nodeId }) {
1472
1513
  const node = useNodeTyped(nodeId, "unknown");
1473
1514
  if (!node) return null;
@@ -1476,13 +1517,13 @@ function UnknownCard({ nodeId }) {
1476
1517
  "Unknown: ",
1477
1518
  node.eventType
1478
1519
  ] }),
1479
- /* @__PURE__ */ jsx15("pre", { className: "lax-unknown-card__data", children: JSON.stringify(node.rawData, null, 2) })
1520
+ /* @__PURE__ */ jsx16("pre", { className: "lax-unknown-card__data", children: JSON.stringify(node.rawData, null, 2) })
1480
1521
  ] });
1481
1522
  }
1482
1523
 
1483
1524
  // src/view/nodes/PermissionNode.tsx
1484
1525
  import { useState as useState9 } from "react";
1485
- import { jsx as jsx16, jsxs as jsxs13 } from "react/jsx-runtime";
1526
+ import { jsx as jsx17, jsxs as jsxs13 } from "react/jsx-runtime";
1486
1527
  function PermissionCard({ nodeId }) {
1487
1528
  const node = useNodeTyped(nodeId, "permission");
1488
1529
  const bus = useInteractionBus();
@@ -1505,22 +1546,22 @@ function PermissionCard({ nodeId }) {
1505
1546
  "data-request-id": node.requestId,
1506
1547
  children: [
1507
1548
  /* @__PURE__ */ jsxs13("div", { className: "lax-permission-card__header", children: [
1508
- /* @__PURE__ */ jsx16("span", { className: "lax-permission-card__label", children: "Permission" }),
1509
- /* @__PURE__ */ jsx16("span", { className: "lax-permission-card__tool", children: node.toolName })
1549
+ /* @__PURE__ */ jsx17("span", { className: "lax-permission-card__label", children: "Permission" }),
1550
+ /* @__PURE__ */ jsx17("span", { className: "lax-permission-card__tool", children: node.toolName })
1510
1551
  ] }),
1511
- /* @__PURE__ */ jsx16("div", { className: "lax-permission-card__message", children: node.message }),
1512
- node.askPrompt && node.askPrompt !== node.message ? /* @__PURE__ */ jsx16("div", { className: "lax-permission-card__prompt", children: node.askPrompt }) : null,
1552
+ /* @__PURE__ */ jsx17("div", { className: "lax-permission-card__message", children: node.message }),
1553
+ node.askPrompt && node.askPrompt !== node.message ? /* @__PURE__ */ jsx17("div", { className: "lax-permission-card__prompt", children: node.askPrompt }) : null,
1513
1554
  pending ? /* @__PURE__ */ jsxs13("div", { className: "lax-permission-card__actions", children: [
1514
- /* @__PURE__ */ jsx16("button", { type: "button", className: "lax-permission-card__allow", onClick: onAllow, children: "Allow" }),
1515
- /* @__PURE__ */ jsx16("button", { type: "button", className: "lax-permission-card__deny", onClick: onDeny, children: "Deny" })
1516
- ] }) : /* @__PURE__ */ jsx16("div", { className: "lax-permission-card__resolved", children: "Resolved" })
1555
+ /* @__PURE__ */ jsx17("button", { type: "button", className: "lax-permission-card__allow", onClick: onAllow, children: "Allow" }),
1556
+ /* @__PURE__ */ jsx17("button", { type: "button", className: "lax-permission-card__deny", onClick: onDeny, children: "Deny" })
1557
+ ] }) : /* @__PURE__ */ jsx17("div", { className: "lax-permission-card__resolved", children: "Resolved" })
1517
1558
  ]
1518
1559
  }
1519
1560
  );
1520
1561
  }
1521
1562
 
1522
1563
  // src/view/nodes/MemorySavedNode.tsx
1523
- import { jsx as jsx17, jsxs as jsxs14 } from "react/jsx-runtime";
1564
+ import { jsx as jsx18, jsxs as jsxs14 } from "react/jsx-runtime";
1524
1565
  function MemorySavedRow({ nodeId }) {
1525
1566
  const node = useNodeTyped(nodeId, "memory_saved");
1526
1567
  if (!node) return null;
@@ -1533,10 +1574,10 @@ function MemorySavedRow({ nodeId }) {
1533
1574
  "data-node-id": nodeId,
1534
1575
  children: [
1535
1576
  /* @__PURE__ */ jsxs14("summary", { className: "lax-memory-saved__summary", children: [
1536
- /* @__PURE__ */ jsx17("span", { className: "lax-memory-saved__icon", "aria-hidden": "true", children: "\u{1F4BE}" }),
1537
- /* @__PURE__ */ jsx17("span", { className: "lax-memory-saved__hint", children: node.displayHint })
1577
+ /* @__PURE__ */ jsx18("span", { className: "lax-memory-saved__icon", "aria-hidden": "true", children: "\u{1F4BE}" }),
1578
+ /* @__PURE__ */ jsx18("span", { className: "lax-memory-saved__hint", children: node.displayHint })
1538
1579
  ] }),
1539
- hasPaths ? /* @__PURE__ */ jsx17("ul", { className: "lax-memory-saved__paths", children: node.writtenPaths.map((p) => /* @__PURE__ */ jsx17("li", { className: "lax-memory-saved__path", children: /* @__PURE__ */ jsx17("code", { children: p }) }, p)) }) : null
1580
+ hasPaths ? /* @__PURE__ */ jsx18("ul", { className: "lax-memory-saved__paths", children: node.writtenPaths.map((p) => /* @__PURE__ */ jsx18("li", { className: "lax-memory-saved__path", children: /* @__PURE__ */ jsx18("code", { children: p }) }, p)) }) : null
1540
1581
  ]
1541
1582
  }
1542
1583
  );
@@ -1757,7 +1798,7 @@ function createActiveSessionBridge(multiStore) {
1757
1798
 
1758
1799
  // src/view/MultiAgentSession.tsx
1759
1800
  import { useEffect as useEffect8, useMemo as useMemo2, useRef as useRef7 } from "react";
1760
- import { jsx as jsx18, jsxs as jsxs15 } from "react/jsx-runtime";
1801
+ import { jsx as jsx19, jsxs as jsxs15 } from "react/jsx-runtime";
1761
1802
  function DebugPanel() {
1762
1803
  const status = useSessionStatus();
1763
1804
  const errors = useInternalErrors();
@@ -1767,7 +1808,7 @@ function DebugPanel() {
1767
1808
  "status: ",
1768
1809
  status
1769
1810
  ] }),
1770
- /* @__PURE__ */ jsx18("ul", { children: errors.map((err, i) => /* @__PURE__ */ jsxs15("li", { children: [
1811
+ /* @__PURE__ */ jsx19("ul", { children: errors.map((err, i) => /* @__PURE__ */ jsxs15("li", { children: [
1771
1812
  "[",
1772
1813
  err.eventType,
1773
1814
  "] ",
@@ -1858,8 +1899,8 @@ function MultiAgentSession({
1858
1899
  for (const c of controllers) c.abort();
1859
1900
  };
1860
1901
  }, [sessions, onError]);
1861
- return /* @__PURE__ */ jsx18(MultiSessionStoreContext.Provider, { value: multiStoreRef.current, children: /* @__PURE__ */ jsx18(SessionStoreContext.Provider, { value: bridgeRef.current, children: /* @__PURE__ */ jsx18(InteractionBusContext.Provider, { value: busRef, children: /* @__PURE__ */ jsx18(NodeRegistryContext.Provider, { value: registryRef, children: /* @__PURE__ */ jsx18(MarkdownRendererContext.Provider, { value: markdownRenderer, children: /* @__PURE__ */ jsx18(ToolDisplayOptionsContext.Provider, { value: toolDisplayRef, children: /* @__PURE__ */ jsx18(SessionViewOptionsContext.Provider, { value: sessionViewRef, children: /* @__PURE__ */ jsxs15("div", { className: "lax-agent-session lax-multi-agent-session", "data-testid": "lax-multi-agent-session", children: [
1862
- children ?? /* @__PURE__ */ jsx18(
1902
+ return /* @__PURE__ */ jsx19(MultiSessionStoreContext.Provider, { value: multiStoreRef.current, children: /* @__PURE__ */ jsx19(SessionStoreContext.Provider, { value: bridgeRef.current, children: /* @__PURE__ */ jsx19(InteractionBusContext.Provider, { value: busRef, children: /* @__PURE__ */ jsx19(NodeRegistryContext.Provider, { value: registryRef, children: /* @__PURE__ */ jsx19(MarkdownRendererContext.Provider, { value: markdownRenderer, children: /* @__PURE__ */ jsx19(ToolDisplayOptionsContext.Provider, { value: toolDisplayRef, children: /* @__PURE__ */ jsx19(SessionViewOptionsContext.Provider, { value: sessionViewRef, children: /* @__PURE__ */ jsxs15("div", { className: "lax-agent-session lax-multi-agent-session", "data-testid": "lax-multi-agent-session", children: [
1903
+ children ?? /* @__PURE__ */ jsx19(
1863
1904
  SessionTimeline,
1864
1905
  {
1865
1906
  virtualized,
@@ -1867,7 +1908,7 @@ function MultiAgentSession({
1867
1908
  groupParallelTools
1868
1909
  }
1869
1910
  ),
1870
- debug ? /* @__PURE__ */ jsx18(DebugPanel, {}) : null
1911
+ debug ? /* @__PURE__ */ jsx19(DebugPanel, {}) : null
1871
1912
  ] }) }) }) }) }) }) }) });
1872
1913
  }
1873
1914
 
@@ -1897,4 +1938,4 @@ export {
1897
1938
  createActiveSessionBridge,
1898
1939
  MultiAgentSession
1899
1940
  };
1900
- //# sourceMappingURL=chunk-YHCK76OU.js.map
1941
+ //# sourceMappingURL=chunk-7TBPTIAP.js.map