|
@@ -1,18 +1,24 @@
|
|
|
/** Turn-aware trajectory event ledger with a local record inspector. */
|
|
/** Turn-aware trajectory event ledger with a local record inspector. */
|
|
|
|
|
|
|
|
-import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react'
|
|
|
|
|
|
|
+import { useCallback, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from 'react'
|
|
|
import type { CSSProperties, ReactNode } from 'react'
|
|
import type { CSSProperties, ReactNode } from 'react'
|
|
|
import { useVirtualizer } from '@tanstack/react-virtual'
|
|
import { useVirtualizer } from '@tanstack/react-virtual'
|
|
|
import {
|
|
import {
|
|
|
|
|
+ CodeBlock,
|
|
|
|
|
+ IconCheckOutline16,
|
|
|
IconChevronRightOutline14,
|
|
IconChevronRightOutline14,
|
|
|
|
|
+ IconCodeOutline16,
|
|
|
|
|
+ IconWrapLinesOutline16,
|
|
|
|
|
+ IconCopyOutline16,
|
|
|
IconSettingsOutline16,
|
|
IconSettingsOutline16,
|
|
|
IconSparkle16,
|
|
IconSparkle16,
|
|
|
IconUserOutline16,
|
|
IconUserOutline16,
|
|
|
JsonTree,
|
|
JsonTree,
|
|
|
MarkdownText,
|
|
MarkdownText,
|
|
|
Tooltip,
|
|
Tooltip,
|
|
|
|
|
+ writeClipboard,
|
|
|
} from '@deepseek-ai/dsh-client-ui-primitives'
|
|
} from '@deepseek-ai/dsh-client-ui-primitives'
|
|
|
-import type { JsonTreeLabels, MarkdownLabels } from '@deepseek-ai/dsh-client-ui-primitives'
|
|
|
|
|
|
|
+import type { JsonTreeLabels, JsonTreeProps, MarkdownLabels } from '@deepseek-ai/dsh-client-ui-primitives'
|
|
|
import { structuredPatch } from 'diff'
|
|
import { structuredPatch } from 'diff'
|
|
|
import type { ImageAttachmentRef } from '@deepseek-ai/dsh-attachment'
|
|
import type { ImageAttachmentRef } from '@deepseek-ai/dsh-attachment'
|
|
|
import type {
|
|
import type {
|
|
@@ -30,6 +36,7 @@ import type { TrajectoryTurnModel } from './layout.ts'
|
|
|
import { trajectoryPreviewText } from './trajectory-preview.ts'
|
|
import { trajectoryPreviewText } from './trajectory-preview.ts'
|
|
|
import type { TrajectoryKey, TrajectoryTranslate } from './locales.ts'
|
|
import type { TrajectoryKey, TrajectoryTranslate } from './locales.ts'
|
|
|
import { COMPACTION_INTERRUPTED_ERROR } from './copy-codes.ts'
|
|
import { COMPACTION_INTERRUPTED_ERROR } from './copy-codes.ts'
|
|
|
|
|
+import { codeProgram, PTC_TOOL_NAME, type CodeProgram } from './code-program.ts'
|
|
|
import css from './TrajectoryTable.module.css'
|
|
import css from './TrajectoryTable.module.css'
|
|
|
|
|
|
|
|
const BOTTOM_FOLLOW_THRESHOLD_PX = 2
|
|
const BOTTOM_FOLLOW_THRESHOLD_PX = 2
|
|
@@ -183,6 +190,7 @@ interface ParentRecords {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
interface ToolCallTextParts {
|
|
interface ToolCallTextParts {
|
|
|
|
|
+ program: boolean
|
|
|
name: string
|
|
name: string
|
|
|
args?: string
|
|
args?: string
|
|
|
}
|
|
}
|
|
@@ -232,8 +240,8 @@ function jsonTreeLabels(t: TrajectoryTranslate): JsonTreeLabels {
|
|
|
copyCompactJson: t('copy.compactJson'),
|
|
copyCompactJson: t('copy.compactJson'),
|
|
|
copied: t('copied'),
|
|
copied: t('copied'),
|
|
|
copyFailed: t('copy.failed'),
|
|
copyFailed: t('copy.failed'),
|
|
|
- collapseNode: t('json.collapseNode'),
|
|
|
|
|
- expandNode: t('json.expandNode'),
|
|
|
|
|
|
|
+ collapseNode: t('collapse'),
|
|
|
|
|
+ expandNode: t('expand'),
|
|
|
copyButtonTitle: action => t('copy.optionsHint', { action }),
|
|
copyButtonTitle: action => t('copy.optionsHint', { action }),
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -376,6 +384,8 @@ function AssistantTimingPanel({
|
|
|
|
|
|
|
|
/** Props for the trajectory ledger. */
|
|
/** Props for the trajectory ledger. */
|
|
|
export interface TrajectoryTableProps {
|
|
export interface TrajectoryTableProps {
|
|
|
|
|
+ /** Wrapping control shared by all JSON inspectors. */
|
|
|
|
|
+ stringWrapping?: JsonTreeProps['stringWrapping']
|
|
|
/** Trajectory locale seat. */
|
|
/** Trajectory locale seat. */
|
|
|
t: TrajectoryTranslate
|
|
t: TrajectoryTranslate
|
|
|
/** Slot-backed durable image renderer shared with the Chat gallery. */
|
|
/** Slot-backed durable image renderer shared with the Chat gallery. */
|
|
@@ -844,10 +854,12 @@ function RequestUsagePanel({
|
|
|
function RequestOptions({
|
|
function RequestOptions({
|
|
|
options,
|
|
options,
|
|
|
preview = false,
|
|
preview = false,
|
|
|
|
|
+ stringWrapping,
|
|
|
t,
|
|
t,
|
|
|
}: {
|
|
}: {
|
|
|
options: AssistantRequestConfig | undefined
|
|
options: AssistantRequestConfig | undefined
|
|
|
preview?: boolean
|
|
preview?: boolean
|
|
|
|
|
+ stringWrapping: JsonTreeProps['stringWrapping']
|
|
|
t: TrajectoryTranslate
|
|
t: TrajectoryTranslate
|
|
|
}) {
|
|
}) {
|
|
|
if (options === undefined) {
|
|
if (options === undefined) {
|
|
@@ -856,6 +868,8 @@ function RequestOptions({
|
|
|
return (
|
|
return (
|
|
|
<JsonTree
|
|
<JsonTree
|
|
|
data={options}
|
|
data={options}
|
|
|
|
|
+ stringWrapping={stringWrapping}
|
|
|
|
|
+ collapsedStringLines={preview ? 3 : 12}
|
|
|
label={t('options.json')}
|
|
label={t('options.json')}
|
|
|
labels={jsonTreeLabels(t)}
|
|
labels={jsonTreeLabels(t)}
|
|
|
className={preview ? css.jsonPreview : css.jsonPayload}
|
|
className={preview ? css.jsonPreview : css.jsonPayload}
|
|
@@ -886,7 +900,11 @@ function messageSourceLabel(source: unknown, t: TrajectoryTranslate): string {
|
|
|
return `${kind[0]?.toUpperCase() ?? ''}${kind.slice(1)}`
|
|
return `${kind[0]?.toUpperCase() ?? ''}${kind.slice(1)}`
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function MessageSource({ record, t }: { record: TableRecord; t: TrajectoryTranslate }) {
|
|
|
|
|
|
|
+function MessageSource({ record, stringWrapping, t }: {
|
|
|
|
|
+ record: TableRecord
|
|
|
|
|
+ stringWrapping: JsonTreeProps['stringWrapping']
|
|
|
|
|
+ t: TrajectoryTranslate
|
|
|
|
|
+}) {
|
|
|
const source = record.cell.messageSource
|
|
const source = record.cell.messageSource
|
|
|
if (source === undefined) return <p className={css.noPayload}>{t('source.notRecorded')}</p>
|
|
if (source === undefined) return <p className={css.noPayload}>{t('source.notRecorded')}</p>
|
|
|
const data = typeof source === 'object' && source !== null
|
|
const data = typeof source === 'object' && source !== null
|
|
@@ -895,6 +913,8 @@ function MessageSource({ record, t }: { record: TableRecord; t: TrajectoryTransl
|
|
|
return (
|
|
return (
|
|
|
<JsonTree
|
|
<JsonTree
|
|
|
data={data}
|
|
data={data}
|
|
|
|
|
+ stringWrapping={stringWrapping}
|
|
|
|
|
+ collapsedStringLines={12}
|
|
|
label={t('source.messageJson')}
|
|
label={t('source.messageJson')}
|
|
|
labels={jsonTreeLabels(t)}
|
|
labels={jsonTreeLabels(t)}
|
|
|
className={css.jsonPayload}
|
|
className={css.jsonPayload}
|
|
@@ -979,8 +999,11 @@ function detailTabs(record: TableRecord): readonly DetailTabItem[] {
|
|
|
}
|
|
}
|
|
|
return [
|
|
return [
|
|
|
{ id: 'overview', labelKey: 'tab.summary' },
|
|
{ id: 'overview', labelKey: 'tab.summary' },
|
|
|
- ...(record.cell.inputDetail ? [{ id: 'input', labelKey: 'tab.payload' } as const] : []),
|
|
|
|
|
- ...(record.cell.outputDetail ? [{ id: 'output', labelKey: 'tab.result' } as const] : []),
|
|
|
|
|
|
|
+ ...(record.cell.inputDetail ? [{
|
|
|
|
|
+ id: 'input', labelKey: codeProgram(record.cell) === undefined ? 'tab.payload' : 'code.source',
|
|
|
|
|
+ } as const] : []),
|
|
|
|
|
+ ...(record.cell.outputDetail || codeProgram(record.cell) !== undefined
|
|
|
|
|
+ ? [{ id: 'output', labelKey: 'tab.result' } as const] : []),
|
|
|
{ id: 'schema', labelKey: 'tab.schema' },
|
|
{ id: 'schema', labelKey: 'tab.schema' },
|
|
|
{ id: 'timing', labelKey: 'tab.timing' },
|
|
{ id: 'timing', labelKey: 'tab.timing' },
|
|
|
]
|
|
]
|
|
@@ -988,6 +1011,8 @@ function detailTabs(record: TableRecord): readonly DetailTabItem[] {
|
|
|
|
|
|
|
|
function recordDisplayText(cell: TrajectoryCellProps, t: TrajectoryTranslate): string {
|
|
function recordDisplayText(cell: TrajectoryCellProps, t: TrajectoryTranslate): string {
|
|
|
if (isToolCallOnly(cell, t)) return ''
|
|
if (isToolCallOnly(cell, t)) return ''
|
|
|
|
|
+ const program = codeProgram(cell)
|
|
|
|
|
+ if (program !== undefined) return `${PTC_TOOL_NAME} · ${program.description.replace(/\s+/g, ' ')}`
|
|
|
if (cell.previewMarkdown !== undefined) {
|
|
if (cell.previewMarkdown !== undefined) {
|
|
|
const preview = trajectoryPreviewText(cell.previewMarkdown)
|
|
const preview = trajectoryPreviewText(cell.previewMarkdown)
|
|
|
if (cell.text === '') return preview
|
|
if (cell.text === '') return preview
|
|
@@ -1009,13 +1034,15 @@ function recordResultText(cell: TrajectoryCellProps): string | undefined {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function toolCallTextParts(
|
|
function toolCallTextParts(
|
|
|
- kind: TrajectoryCellKind,
|
|
|
|
|
|
|
+ cell: TrajectoryCellProps,
|
|
|
text: string,
|
|
text: string,
|
|
|
): ToolCallTextParts | undefined {
|
|
): ToolCallTextParts | undefined {
|
|
|
- if (kind !== 'tool' && kind !== 'subtool') return undefined
|
|
|
|
|
|
|
+ if (cell.kind !== 'tool' && cell.kind !== 'subtool') return undefined
|
|
|
|
|
+ const program = cell.toolName === PTC_TOOL_NAME
|
|
|
const separator = text.indexOf(' · ')
|
|
const separator = text.indexOf(' · ')
|
|
|
- if (separator === -1) return { name: text }
|
|
|
|
|
|
|
+ if (separator === -1) return { name: text, program }
|
|
|
return {
|
|
return {
|
|
|
|
|
+ program,
|
|
|
name: text.slice(0, separator),
|
|
name: text.slice(0, separator),
|
|
|
args: text.slice(separator + 3),
|
|
args: text.slice(separator + 3),
|
|
|
}
|
|
}
|
|
@@ -1048,7 +1075,7 @@ function RecordPresentation({
|
|
|
const displayText = useMemo(
|
|
const displayText = useMemo(
|
|
|
() => recordDisplayText(cell, t),
|
|
() => recordDisplayText(cell, t),
|
|
|
[
|
|
[
|
|
|
- cell.kind, cell.text, cell.previewMarkdown,
|
|
|
|
|
|
|
+ cell.kind, cell.text, cell.toolName, cell.previewMarkdown,
|
|
|
cell.inputDetail, cell.outputDetail, cell.thinkingDetail, t,
|
|
cell.inputDetail, cell.outputDetail, cell.thinkingDetail, t,
|
|
|
],
|
|
],
|
|
|
)
|
|
)
|
|
@@ -1057,7 +1084,7 @@ function RecordPresentation({
|
|
|
[cell.result, cell.resultPreviewMarkdown],
|
|
[cell.result, cell.resultPreviewMarkdown],
|
|
|
)
|
|
)
|
|
|
const toolCallOnly = isToolCallOnly(cell, t)
|
|
const toolCallOnly = isToolCallOnly(cell, t)
|
|
|
- const toolCallText = toolCallTextParts(cell.kind, displayText)
|
|
|
|
|
|
|
+ const toolCallText = toolCallTextParts(cell, displayText)
|
|
|
const listDisplayText = toolCallOnly
|
|
const listDisplayText = toolCallOnly
|
|
|
? t('record.toolCallOnly')
|
|
? t('record.toolCallOnly')
|
|
|
: toolCallText === undefined
|
|
: toolCallText === undefined
|
|
@@ -1087,10 +1114,11 @@ function RecordListText({
|
|
|
return (
|
|
return (
|
|
|
<>
|
|
<>
|
|
|
<span className={css.toolCallNameTypeface}>
|
|
<span className={css.toolCallNameTypeface}>
|
|
|
|
|
+ {toolCallText.program && <IconCodeOutline16 className={css.programIcon} size={12} />}
|
|
|
{toolCallText.name || '—'}
|
|
{toolCallText.name || '—'}
|
|
|
</span>
|
|
</span>
|
|
|
{toolCallText.args !== undefined && (
|
|
{toolCallText.args !== undefined && (
|
|
|
- <span className={css.toolCallPayload}>
|
|
|
|
|
|
|
+ <span className={toolCallText.program ? css.programSummary : css.toolCallPayload}>
|
|
|
{toolCallText.args}
|
|
{toolCallText.args}
|
|
|
</span>
|
|
</span>
|
|
|
)}
|
|
)}
|
|
@@ -1281,8 +1309,13 @@ function ToolGlyph() {
|
|
|
|
|
|
|
|
function ToolCatalog({
|
|
function ToolCatalog({
|
|
|
tools,
|
|
tools,
|
|
|
|
|
+ stringWrapping,
|
|
|
t,
|
|
t,
|
|
|
-}: { tools: ConversationPromptSnapshot['tools']; t: TrajectoryTranslate }) {
|
|
|
|
|
|
|
+}: {
|
|
|
|
|
+ tools: ConversationPromptSnapshot['tools']
|
|
|
|
|
+ stringWrapping: JsonTreeProps['stringWrapping']
|
|
|
|
|
+ t: TrajectoryTranslate
|
|
|
|
|
+}) {
|
|
|
if (tools.length === 0) return <p className={css.noPayload}>{t('record.toolsMissing')}</p>
|
|
if (tools.length === 0) return <p className={css.noPayload}>{t('record.toolsMissing')}</p>
|
|
|
return (
|
|
return (
|
|
|
<div className={css.toolCatalog}>
|
|
<div className={css.toolCatalog}>
|
|
@@ -1300,6 +1333,7 @@ function ToolCatalog({
|
|
|
)}
|
|
)}
|
|
|
<JsonTree
|
|
<JsonTree
|
|
|
data={tool.parameters}
|
|
data={tool.parameters}
|
|
|
|
|
+ stringWrapping={stringWrapping}
|
|
|
label={t('record.namedParametersJson', { name: tool.name })}
|
|
label={t('record.namedParametersJson', { name: tool.name })}
|
|
|
labels={jsonTreeLabels(t)}
|
|
labels={jsonTreeLabels(t)}
|
|
|
className={css.toolCatalogTree}
|
|
className={css.toolCatalogTree}
|
|
@@ -1544,14 +1578,20 @@ function MarkdownRecordContent({
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-function RecordTiming({ record, t }: { record: TableRecord; t: TrajectoryTranslate }) {
|
|
|
|
|
|
|
+function RecordTiming({
|
|
|
|
|
+ record,
|
|
|
|
|
+ preview = false,
|
|
|
|
|
+ t,
|
|
|
|
|
+}: { record: TableRecord; preview?: boolean; t: TrajectoryTranslate }) {
|
|
|
return record.cell.kind === 'message' && record.cell.assistantMetrics !== undefined
|
|
return record.cell.kind === 'message' && record.cell.assistantMetrics !== undefined
|
|
|
? <AssistantTimingPanel metrics={record.cell.assistantMetrics} t={t} />
|
|
? <AssistantTimingPanel metrics={record.cell.assistantMetrics} t={t} />
|
|
|
: (
|
|
: (
|
|
|
<dl className={css.overview}>
|
|
<dl className={css.overview}>
|
|
|
<div><dt>{t('timing.started')}</dt><StartedAtValue timestamp={record.cell.startedAt ?? null} t={t} /></div>
|
|
<div><dt>{t('timing.started')}</dt><StartedAtValue timestamp={record.cell.startedAt ?? null} t={t} /></div>
|
|
|
<div><dt>{t('timing.duration')}</dt><dd>{formatElapsedSeconds(record.cell.timeSeconds, t)}</dd></div>
|
|
<div><dt>{t('timing.duration')}</dt><dd>{formatElapsedSeconds(record.cell.timeSeconds, t)}</dd></div>
|
|
|
- <div><dt>{t('timing.source')}</dt><dd>{record.cell.timeSeconds === null ? t('timing.notAvailable') : t('timing.sessionTimestamps')}</dd></div>
|
|
|
|
|
|
|
+ {!preview && (
|
|
|
|
|
+ <div><dt>{t('timing.source')}</dt><dd>{record.cell.timeSeconds === null ? t('timing.notAvailable') : t('timing.sessionTimestamps')}</dd></div>
|
|
|
|
|
+ )}
|
|
|
</dl>
|
|
</dl>
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|
|
@@ -1560,14 +1600,16 @@ function RequestTiming({
|
|
|
assistant,
|
|
assistant,
|
|
|
anchor,
|
|
anchor,
|
|
|
request,
|
|
request,
|
|
|
|
|
+ preview = false,
|
|
|
t,
|
|
t,
|
|
|
}: {
|
|
}: {
|
|
|
assistant: TableRecord | undefined
|
|
assistant: TableRecord | undefined
|
|
|
anchor: TableRecord | undefined
|
|
anchor: TableRecord | undefined
|
|
|
request: TrajectoryRequestNumber | undefined
|
|
request: TrajectoryRequestNumber | undefined
|
|
|
|
|
+ preview?: boolean
|
|
|
t: TrajectoryTranslate
|
|
t: TrajectoryTranslate
|
|
|
}) {
|
|
}) {
|
|
|
- if (assistant !== undefined) return <RecordTiming record={assistant} t={t} />
|
|
|
|
|
|
|
+ if (assistant !== undefined) return <RecordTiming record={assistant} preview={preview} t={t} />
|
|
|
if (request?.startedAt !== undefined) {
|
|
if (request?.startedAt !== undefined) {
|
|
|
const duration = request.completedAt === null || request.completedAt === undefined
|
|
const duration = request.completedAt === null || request.completedAt === undefined
|
|
|
? null
|
|
? null
|
|
@@ -1576,10 +1618,12 @@ function RequestTiming({
|
|
|
<dl className={css.overview}>
|
|
<dl className={css.overview}>
|
|
|
<div><dt>{t('timing.started')}</dt><StartedAtValue timestamp={request.startedAt} t={t} /></div>
|
|
<div><dt>{t('timing.started')}</dt><StartedAtValue timestamp={request.startedAt} t={t} /></div>
|
|
|
<div><dt>{t('timing.duration')}</dt><dd>{formatElapsedSeconds(duration, t)}</dd></div>
|
|
<div><dt>{t('timing.duration')}</dt><dd>{formatElapsedSeconds(duration, t)}</dd></div>
|
|
|
- <div>
|
|
|
|
|
- <dt>{t('timing.source')}</dt>
|
|
|
|
|
- <dd>{duration === null ? t('timing.sessionTimestampsRunning') : t('timing.sessionTimestamps')}</dd>
|
|
|
|
|
- </div>
|
|
|
|
|
|
|
+ {!preview && (
|
|
|
|
|
+ <div>
|
|
|
|
|
+ <dt>{t('timing.source')}</dt>
|
|
|
|
|
+ <dd>{duration === null ? t('timing.sessionTimestampsRunning') : t('timing.sessionTimestamps')}</dd>
|
|
|
|
|
+ </div>
|
|
|
|
|
+ )}
|
|
|
</dl>
|
|
</dl>
|
|
|
)
|
|
)
|
|
|
}
|
|
}
|
|
@@ -1599,12 +1643,14 @@ function RecordPayload({
|
|
|
direction,
|
|
direction,
|
|
|
preview = false,
|
|
preview = false,
|
|
|
renderImages,
|
|
renderImages,
|
|
|
|
|
+ stringWrapping,
|
|
|
t,
|
|
t,
|
|
|
}: {
|
|
}: {
|
|
|
record: TableRecord
|
|
record: TableRecord
|
|
|
direction: 'input' | 'output'
|
|
direction: 'input' | 'output'
|
|
|
preview?: boolean
|
|
preview?: boolean
|
|
|
renderImages: RenderMessageImages
|
|
renderImages: RenderMessageImages
|
|
|
|
|
+ stringWrapping: JsonTreeProps['stringWrapping']
|
|
|
t: TrajectoryTranslate
|
|
t: TrajectoryTranslate
|
|
|
}) {
|
|
}) {
|
|
|
const value = direction === 'input' ? record.cell.inputDetail : record.cell.outputDetail
|
|
const value = direction === 'input' ? record.cell.inputDetail : record.cell.outputDetail
|
|
@@ -1624,6 +1670,8 @@ function RecordPayload({
|
|
|
return (
|
|
return (
|
|
|
<JsonTree
|
|
<JsonTree
|
|
|
data={json}
|
|
data={json}
|
|
|
|
|
+ stringWrapping={stringWrapping}
|
|
|
|
|
+ collapsedStringLines={preview ? 3 : 12}
|
|
|
label={t('record.resultJson')}
|
|
label={t('record.resultJson')}
|
|
|
labels={jsonTreeLabels(t)}
|
|
labels={jsonTreeLabels(t)}
|
|
|
className={payloadClassName}
|
|
className={payloadClassName}
|
|
@@ -1668,6 +1716,8 @@ function RecordPayload({
|
|
|
return (
|
|
return (
|
|
|
<JsonTree
|
|
<JsonTree
|
|
|
data={json}
|
|
data={json}
|
|
|
|
|
+ stringWrapping={stringWrapping}
|
|
|
|
|
+ collapsedStringLines={preview ? 3 : 12}
|
|
|
label={t(direction === 'input' ? 'record.payloadJson' : 'record.outputJson')}
|
|
label={t(direction === 'input' ? 'record.payloadJson' : 'record.outputJson')}
|
|
|
labels={jsonTreeLabels(t)}
|
|
labels={jsonTreeLabels(t)}
|
|
|
className={payloadClassName}
|
|
className={payloadClassName}
|
|
@@ -1690,10 +1740,12 @@ function RecordPayload({
|
|
|
function RecordSchema({
|
|
function RecordSchema({
|
|
|
record,
|
|
record,
|
|
|
preview = false,
|
|
preview = false,
|
|
|
|
|
+ stringWrapping,
|
|
|
t,
|
|
t,
|
|
|
}: {
|
|
}: {
|
|
|
record: TableRecord
|
|
record: TableRecord
|
|
|
preview?: boolean
|
|
preview?: boolean
|
|
|
|
|
+ stringWrapping: JsonTreeProps['stringWrapping']
|
|
|
t: TrajectoryTranslate
|
|
t: TrajectoryTranslate
|
|
|
}) {
|
|
}) {
|
|
|
if (!record.cell.schemaDetail) {
|
|
if (!record.cell.schemaDetail) {
|
|
@@ -1711,6 +1763,8 @@ function RecordSchema({
|
|
|
<h4 className={css.schemaParametersTitle}>{t('record.parameters')}</h4>
|
|
<h4 className={css.schemaParametersTitle}>{t('record.parameters')}</h4>
|
|
|
<JsonTree
|
|
<JsonTree
|
|
|
data={schema.parameters}
|
|
data={schema.parameters}
|
|
|
|
|
+ stringWrapping={stringWrapping}
|
|
|
|
|
+ collapsedStringLines={preview ? 3 : 12}
|
|
|
label={t('record.namedParametersJson', { name: schema.name })}
|
|
label={t('record.namedParametersJson', { name: schema.name })}
|
|
|
labels={jsonTreeLabels(t)}
|
|
labels={jsonTreeLabels(t)}
|
|
|
className={css.schemaTree}
|
|
className={css.schemaTree}
|
|
@@ -1763,15 +1817,174 @@ function parseJsonContainer(value: string): object | undefined {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+function InspectorCopyButton({ text, label, t }: {
|
|
|
|
|
+ text: string
|
|
|
|
|
+ label: string
|
|
|
|
|
+ t: TrajectoryTranslate
|
|
|
|
|
+}) {
|
|
|
|
|
+ const [state, setState] = useState<'idle' | 'copied' | 'failed'>('idle')
|
|
|
|
|
+ useEffect(() => {
|
|
|
|
|
+ if (state === 'idle') return
|
|
|
|
|
+ const timer = setTimeout(() => { setState('idle') }, 1_500)
|
|
|
|
|
+ return () => { clearTimeout(timer) }
|
|
|
|
|
+ }, [state])
|
|
|
|
|
+ const title = state === 'idle' ? label : t(state === 'copied' ? 'copied' : 'copy.failed')
|
|
|
|
|
+ return (
|
|
|
|
|
+ <button
|
|
|
|
|
+ type="button"
|
|
|
|
|
+ className={css.programAction}
|
|
|
|
|
+ data-state={state}
|
|
|
|
|
+ aria-label={title}
|
|
|
|
|
+ title={title}
|
|
|
|
|
+ onClick={() => { void writeClipboard(text).then((ok) => { setState(ok ? 'copied' : 'failed') }) }}
|
|
|
|
|
+ >
|
|
|
|
|
+ {state === 'copied' ? <IconCheckOutline16 size={12} /> : <IconCopyOutline16 size={12} />}
|
|
|
|
|
+ </button>
|
|
|
|
|
+ )
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function ProgramInput({ program, initialWrapped, stringWrapping, onOpen, t }: {
|
|
|
|
|
+ program: CodeProgram
|
|
|
|
|
+ initialWrapped: boolean
|
|
|
|
|
+ stringWrapping: JsonTreeProps['stringWrapping']
|
|
|
|
|
+ onOpen?: () => void
|
|
|
|
|
+ t: TrajectoryTranslate
|
|
|
|
|
+}) {
|
|
|
|
|
+ const contentsId = useId()
|
|
|
|
|
+ const [wrapped, setWrapped] = useState(initialWrapped)
|
|
|
|
|
+ const [showJson, setShowJson] = useState(false)
|
|
|
|
|
+ const actions = (
|
|
|
|
|
+ <span className={css.programActions}>
|
|
|
|
|
+ {!showJson && program.language !== undefined && (
|
|
|
|
|
+ <span className={css.programLanguage}>{program.language}</span>
|
|
|
|
|
+ )}
|
|
|
|
|
+ {!showJson && (
|
|
|
|
|
+ <button
|
|
|
|
|
+ type="button"
|
|
|
|
|
+ className={css.programAction}
|
|
|
|
|
+ aria-label={t('record.wrapLines')}
|
|
|
|
|
+ title={t('record.wrapLines')}
|
|
|
|
|
+ aria-pressed={wrapped}
|
|
|
|
|
+ aria-controls={contentsId}
|
|
|
|
|
+ onClick={() => {
|
|
|
|
|
+ const next = !wrapped
|
|
|
|
|
+ setWrapped(next)
|
|
|
|
|
+ stringWrapping?.setDefault(next)
|
|
|
|
|
+ }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <IconWrapLinesOutline16 size={12} />
|
|
|
|
|
+ </button>
|
|
|
|
|
+ )}
|
|
|
|
|
+ {onOpen === undefined && (
|
|
|
|
|
+ <button
|
|
|
|
|
+ type="button"
|
|
|
|
|
+ className={css.programAction}
|
|
|
|
|
+ aria-label={t('code.originalJson')}
|
|
|
|
|
+ title={t('code.originalJson')}
|
|
|
|
|
+ aria-pressed={showJson}
|
|
|
|
|
+ aria-controls={contentsId}
|
|
|
|
|
+ onClick={() => { setShowJson(value => !value) }}
|
|
|
|
|
+ >
|
|
|
|
|
+ <svg width="12" height="12" viewBox="0 0 16 16" fill="none"
|
|
|
|
|
+ stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" aria-hidden="true">
|
|
|
|
|
+ <path d="M6 2H5a2 2 0 0 0-2 2v2a2 2 0 0 1-2 2 2 2 0 0 1 2 2v2a2 2 0 0 0 2 2h1" />
|
|
|
|
|
+ <path d="M10 2h1a2 2 0 0 1 2 2v2a2 2 0 0 0 2 2 2 2 0 0 0-2 2v2a2 2 0 0 1-2 2h-1" />
|
|
|
|
|
+ </svg>
|
|
|
|
|
+ </button>
|
|
|
|
|
+ )}
|
|
|
|
|
+ <InspectorCopyButton
|
|
|
|
|
+ text={showJson ? program.rawInput : program.source}
|
|
|
|
|
+ label={t(showJson ? 'copy.json' : 'code.copySource')}
|
|
|
|
|
+ t={t}
|
|
|
|
|
+ />
|
|
|
|
|
+ </span>
|
|
|
|
|
+ )
|
|
|
|
|
+ const body = (
|
|
|
|
|
+ <div id={contentsId} className={css.programContent} data-wrap={wrapped}>
|
|
|
|
|
+ {showJson
|
|
|
|
|
+ ? <JsonTree data={program.arguments} label={t('record.parametersJson')}
|
|
|
|
|
+ labels={jsonTreeLabels(t)} stringWrapping={stringWrapping} />
|
|
|
|
|
+ : <CodeBlock code={program.source} lang={program.language} lineNumbers showHeader={false}
|
|
|
|
|
+ className={css.programSource} copyLabel={t('code.copySource')} copiedLabel={t('copied')} />}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ )
|
|
|
|
|
+ return onOpen === undefined
|
|
|
|
|
+ ? (
|
|
|
|
|
+ <section className={css.programPanel}>
|
|
|
|
|
+ <header className={css.overviewHeading}>
|
|
|
|
|
+ <span>{t('code.source')}</span>
|
|
|
|
|
+ {actions}
|
|
|
|
|
+ </header>
|
|
|
|
|
+ {body}
|
|
|
|
|
+ </section>
|
|
|
|
|
+ )
|
|
|
|
|
+ : <OverviewSection label={t('code.source')} onOpen={onOpen} actions={actions}>{body}</OverviewSection>
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function ProgramOutput({ record, stringWrapping, onOpen, t }: {
|
|
|
|
|
+ record: TableRecord
|
|
|
|
|
+ stringWrapping: JsonTreeProps['stringWrapping']
|
|
|
|
|
+ onOpen?: () => void
|
|
|
|
|
+ t: TrajectoryTranslate
|
|
|
|
|
+}) {
|
|
|
|
|
+ const output = record.cell.outputDetail
|
|
|
|
|
+ const json = output === undefined || record.cell.isError === true ? undefined : parseJsonContainer(output)
|
|
|
|
|
+ const actions = output === undefined ? undefined : (
|
|
|
|
|
+ <span className={css.programActions}>
|
|
|
|
|
+ <InspectorCopyButton text={output} label={t('code.copyOutput')} t={t} />
|
|
|
|
|
+ </span>
|
|
|
|
|
+ )
|
|
|
|
|
+ const body = (
|
|
|
|
|
+ <div className={css.programContent}>
|
|
|
|
|
+ {output === undefined || output === ''
|
|
|
|
|
+ ? <p className={css.noPayload}>{t(stateOf(record) === 'running' ? 'code.running' : 'record.noOutput')}</p>
|
|
|
|
|
+ : json !== undefined
|
|
|
|
|
+ ? <JsonTree data={json} label={t('record.outputJson')} labels={jsonTreeLabels(t)}
|
|
|
|
|
+ stringWrapping={stringWrapping} collapsedStringLines={onOpen === undefined ? 12 : 3} />
|
|
|
|
|
+ : <pre className={`${css.programOutput} ${record.cell.isError === true ? css.programError : ''}`}>{output}</pre>}
|
|
|
|
|
+ </div>
|
|
|
|
|
+ )
|
|
|
|
|
+ return onOpen === undefined
|
|
|
|
|
+ ? (
|
|
|
|
|
+ <section className={css.programPanel}>
|
|
|
|
|
+ <header className={css.overviewHeading}>
|
|
|
|
|
+ <span>{t('code.output')}</span>
|
|
|
|
|
+ {actions}
|
|
|
|
|
+ </header>
|
|
|
|
|
+ {body}
|
|
|
|
|
+ </section>
|
|
|
|
|
+ )
|
|
|
|
|
+ : <OverviewSection label={t('code.output')} onOpen={onOpen} actions={actions}>{body}</OverviewSection>
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
function OverviewSection({
|
|
function OverviewSection({
|
|
|
label,
|
|
label,
|
|
|
onOpen,
|
|
onOpen,
|
|
|
|
|
+ actions,
|
|
|
children,
|
|
children,
|
|
|
}: {
|
|
}: {
|
|
|
label: string
|
|
label: string
|
|
|
onOpen: () => void
|
|
onOpen: () => void
|
|
|
|
|
+ actions?: ReactNode
|
|
|
children: ReactNode
|
|
children: ReactNode
|
|
|
}) {
|
|
}) {
|
|
|
|
|
+ const previewRef = useRef<HTMLDivElement>(null)
|
|
|
|
|
+ const [hasMore, setHasMore] = useState(false)
|
|
|
|
|
+ const measureOverflow = useCallback((preview: HTMLElement) => {
|
|
|
|
|
+ setHasMore(preview.scrollHeight - preview.clientHeight - preview.scrollTop > 1)
|
|
|
|
|
+ }, [])
|
|
|
|
|
+
|
|
|
|
|
+ useLayoutEffect(() => {
|
|
|
|
|
+ const preview = previewRef.current as HTMLDivElement
|
|
|
|
|
+ const measure = () => { measureOverflow(preview) }
|
|
|
|
|
+ measure()
|
|
|
|
|
+ if (typeof ResizeObserver === 'undefined') return
|
|
|
|
|
+ const observer = new ResizeObserver(measure)
|
|
|
|
|
+ observer.observe(preview)
|
|
|
|
|
+ for (const child of preview.children) observer.observe(child)
|
|
|
|
|
+ return () => { observer.disconnect() }
|
|
|
|
|
+ }, [children, measureOverflow])
|
|
|
|
|
+
|
|
|
return (
|
|
return (
|
|
|
<section className={css.overviewSection}>
|
|
<section className={css.overviewSection}>
|
|
|
<h3 className={css.overviewHeading}>
|
|
<h3 className={css.overviewHeading}>
|
|
@@ -1783,10 +1996,14 @@ function OverviewSection({
|
|
|
<span>{label}</span>
|
|
<span>{label}</span>
|
|
|
<IconChevronRightOutline14 className={css.overviewTitleIcon} size={12} />
|
|
<IconChevronRightOutline14 className={css.overviewTitleIcon} size={12} />
|
|
|
</button>
|
|
</button>
|
|
|
|
|
+ {actions}
|
|
|
</h3>
|
|
</h3>
|
|
|
<div
|
|
<div
|
|
|
|
|
+ ref={previewRef}
|
|
|
className={`${css.overviewPreview} ${css.summaryScrollRegion}`}
|
|
className={`${css.overviewPreview} ${css.summaryScrollRegion}`}
|
|
|
data-summary-scroll-region=""
|
|
data-summary-scroll-region=""
|
|
|
|
|
+ data-scroll-more={hasMore || undefined}
|
|
|
|
|
+ onScroll={(event) => { measureOverflow(event.currentTarget) }}
|
|
|
>
|
|
>
|
|
|
{children}
|
|
{children}
|
|
|
</div>
|
|
</div>
|
|
@@ -1802,6 +2019,7 @@ function OverviewSection({
|
|
|
*/
|
|
*/
|
|
|
export function TrajectoryTable({
|
|
export function TrajectoryTable({
|
|
|
t,
|
|
t,
|
|
|
|
|
+ stringWrapping,
|
|
|
renderImages,
|
|
renderImages,
|
|
|
requestNumbers: sessionRequestNumbers,
|
|
requestNumbers: sessionRequestNumbers,
|
|
|
turns,
|
|
turns,
|
|
@@ -1828,7 +2046,8 @@ export function TrajectoryTable({
|
|
|
const [selectedRecordId, setSelectedRecordId] = useState<string | null>(null)
|
|
const [selectedRecordId, setSelectedRecordId] = useState<string | null>(null)
|
|
|
const [selectedRequest, setSelectedRequest] = useState<SelectedRequest | null>(null)
|
|
const [selectedRequest, setSelectedRequest] = useState<SelectedRequest | null>(null)
|
|
|
const [activeTab, setActiveTab] = useState<DetailTab>('overview')
|
|
const [activeTab, setActiveTab] = useState<DetailTab>('overview')
|
|
|
- const [thinkingExpanded, setThinkingExpanded] = useState(false)
|
|
|
|
|
|
|
+ const [codeWrappingOnOpen, setCodeWrappingOnOpen] = useState(false)
|
|
|
|
|
+ const [thinkingDisclosure, setThinkingDisclosure] = useState<{ recordId: string; expanded: boolean }>()
|
|
|
const [detailsWidth, setDetailsWidth] = useState<number | null>(null)
|
|
const [detailsWidth, setDetailsWidth] = useState<number | null>(null)
|
|
|
const [toolRequestOffset, setToolRequestOffset] = useState<number | null>(null)
|
|
const [toolRequestOffset, setToolRequestOffset] = useState<number | null>(null)
|
|
|
const detailsResizeDrag = useRef<DetailsResizeDrag | null>(null)
|
|
const detailsResizeDrag = useRef<DetailsResizeDrag | null>(null)
|
|
@@ -1860,6 +2079,16 @@ export function TrajectoryTable({
|
|
|
const selected = selectedTemplate === undefined
|
|
const selected = selectedTemplate === undefined
|
|
|
? undefined
|
|
? undefined
|
|
|
: currentRecord(selectedTemplate)
|
|
: currentRecord(selectedTemplate)
|
|
|
|
|
+ const selectedProgram = selected === undefined ? undefined : codeProgram(selected.cell)
|
|
|
|
|
+ const thinkingExpanded = thinkingDisclosure?.recordId === selectedRecordId
|
|
|
|
|
+ ? thinkingDisclosure.expanded
|
|
|
|
|
+ : selected?.cell.kind === 'message'
|
|
|
|
|
+ && Boolean(selected.cell.thinkingDetail?.trim())
|
|
|
|
|
+ const setThinkingExpanded = (expanded: boolean) => {
|
|
|
|
|
+ if (selectedRecordId !== null) {
|
|
|
|
|
+ setThinkingDisclosure({ recordId: selectedRecordId, expanded })
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
const selectedIndex = selected?.cell.index ?? null
|
|
const selectedIndex = selected?.cell.index ?? null
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
|
onSelectedIndexChange?.(selectedIndex)
|
|
onSelectedIndexChange?.(selectedIndex)
|
|
@@ -2060,6 +2289,7 @@ export function TrajectoryTable({
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const activateTab = (tab: DetailTab) => {
|
|
const activateTab = (tab: DetailTab) => {
|
|
|
|
|
+ setCodeWrappingOnOpen(stringWrapping?.getDefault() ?? false)
|
|
|
tabHistory.current.delete(tab)
|
|
tabHistory.current.delete(tab)
|
|
|
tabHistory.current.add(tab)
|
|
tabHistory.current.add(tab)
|
|
|
setActiveTab(tab)
|
|
setActiveTab(tab)
|
|
@@ -2076,6 +2306,7 @@ export function TrajectoryTable({
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
const selectRecord = useCallback((index: number) => {
|
|
const selectRecord = useCallback((index: number) => {
|
|
|
|
|
+ setCodeWrappingOnOpen(stringWrapping?.getDefault() ?? false)
|
|
|
const record = allRecords.find(candidate => candidate.cell.index === index)
|
|
const record = allRecords.find(candidate => candidate.cell.index === index)
|
|
|
onRecordSelect?.(index)
|
|
onRecordSelect?.(index)
|
|
|
setSelectedRequest(null)
|
|
setSelectedRequest(null)
|
|
@@ -2085,7 +2316,7 @@ export function TrajectoryTable({
|
|
|
const available = new Set(tabs.map(tab => tab.id))
|
|
const available = new Set(tabs.map(tab => tab.id))
|
|
|
const recent = [...tabHistory.current].reverse().find(tab => available.has(tab))
|
|
const recent = [...tabHistory.current].reverse().find(tab => available.has(tab))
|
|
|
setActiveTab(recent ?? tabs[0]?.id ?? 'overview')
|
|
setActiveTab(recent ?? tabs[0]?.id ?? 'overview')
|
|
|
- }, [allRecords, onRecordSelect])
|
|
|
|
|
|
|
+ }, [allRecords, onRecordSelect, stringWrapping])
|
|
|
useEffect(() => {
|
|
useEffect(() => {
|
|
|
if (
|
|
if (
|
|
|
recordSelection === null
|
|
recordSelection === null
|
|
@@ -2809,7 +3040,9 @@ export function TrajectoryTable({
|
|
|
id="trajectory-detail-panel"
|
|
id="trajectory-detail-panel"
|
|
|
className={activeTab === 'overview'
|
|
className={activeTab === 'overview'
|
|
|
? `${css.detailBody} ${css.detailBodySummary}`
|
|
? `${css.detailBody} ${css.detailBodySummary}`
|
|
|
- : css.detailBody}
|
|
|
|
|
|
|
+ : selectedProgram !== undefined && (activeTab === 'input' || activeTab === 'output')
|
|
|
|
|
+ ? `${css.detailBody} ${css.detailBodyProgram}`
|
|
|
|
|
+ : css.detailBody}
|
|
|
role="tabpanel"
|
|
role="tabpanel"
|
|
|
aria-labelledby={`trajectory-detail-${activeTab}`}
|
|
aria-labelledby={`trajectory-detail-${activeTab}`}
|
|
|
>
|
|
>
|
|
@@ -2916,7 +3149,7 @@ export function TrajectoryTable({
|
|
|
<div className={css.overviewSections}>
|
|
<div className={css.overviewSections}>
|
|
|
{selectedRequestOptions !== undefined && (
|
|
{selectedRequestOptions !== undefined && (
|
|
|
<OverviewSection label={t('tab.options')} onOpen={() => { activateTab('options') }}>
|
|
<OverviewSection label={t('tab.options')} onOpen={() => { activateTab('options') }}>
|
|
|
- <RequestOptions options={selectedRequestOptions} preview t={t} />
|
|
|
|
|
|
|
+ <RequestOptions options={selectedRequestOptions} preview stringWrapping={stringWrapping} t={t} />
|
|
|
</OverviewSection>
|
|
</OverviewSection>
|
|
|
)}
|
|
)}
|
|
|
<OverviewSection label={t('tab.usage')} onOpen={() => { activateTab('usage') }}>
|
|
<OverviewSection label={t('tab.usage')} onOpen={() => { activateTab('usage') }}>
|
|
@@ -2927,6 +3160,7 @@ export function TrajectoryTable({
|
|
|
assistant={selectedRequestAssistant}
|
|
assistant={selectedRequestAssistant}
|
|
|
anchor={selectedRequestAnchor}
|
|
anchor={selectedRequestAnchor}
|
|
|
request={selectedRequestInfo}
|
|
request={selectedRequestInfo}
|
|
|
|
|
+ preview
|
|
|
t={t}
|
|
t={t}
|
|
|
/>
|
|
/>
|
|
|
</OverviewSection>
|
|
</OverviewSection>
|
|
@@ -2934,7 +3168,7 @@ export function TrajectoryTable({
|
|
|
</>
|
|
</>
|
|
|
)}
|
|
)}
|
|
|
{selectedRequestInfo !== undefined && activeTab === 'options' && (
|
|
{selectedRequestInfo !== undefined && activeTab === 'options' && (
|
|
|
- <RequestOptions options={selectedRequestOptions} t={t} />
|
|
|
|
|
|
|
+ <RequestOptions options={selectedRequestOptions} stringWrapping={stringWrapping} t={t} />
|
|
|
)}
|
|
)}
|
|
|
{selectedRequestInfo !== undefined && activeTab === 'usage' && (
|
|
{selectedRequestInfo !== undefined && activeTab === 'usage' && (
|
|
|
<RequestUsagePanel
|
|
<RequestUsagePanel
|
|
@@ -2970,7 +3204,7 @@ export function TrajectoryTable({
|
|
|
)
|
|
)
|
|
|
)}
|
|
)}
|
|
|
{selectedPrompt !== undefined && activeTab === 'tools' && (
|
|
{selectedPrompt !== undefined && activeTab === 'tools' && (
|
|
|
- <ToolCatalog tools={selectedPrompt.tools} t={t} />
|
|
|
|
|
|
|
+ <ToolCatalog tools={selectedPrompt.tools} stringWrapping={stringWrapping} t={t} />
|
|
|
)}
|
|
)}
|
|
|
{!promptSelected
|
|
{!promptSelected
|
|
|
&& selected?.cell.kind === 'compacted'
|
|
&& selected?.cell.kind === 'compacted'
|
|
@@ -3020,6 +3254,9 @@ export function TrajectoryTable({
|
|
|
&& selectedState !== undefined
|
|
&& selectedState !== undefined
|
|
|
&& activeTab === 'overview' && (
|
|
&& activeTab === 'overview' && (
|
|
|
<>
|
|
<>
|
|
|
|
|
+ {selectedProgram !== undefined && selectedProgram.description !== '' && (
|
|
|
|
|
+ <p className={css.programDescription}>{selectedProgram.description}</p>
|
|
|
|
|
+ )}
|
|
|
<dl
|
|
<dl
|
|
|
className={`${css.overview} ${css.summaryScrollRegion}`}
|
|
className={`${css.overview} ${css.summaryScrollRegion}`}
|
|
|
data-summary-scroll-region=""
|
|
data-summary-scroll-region=""
|
|
@@ -3111,40 +3348,50 @@ export function TrajectoryTable({
|
|
|
)}
|
|
)}
|
|
|
</dl>
|
|
</dl>
|
|
|
<div className={css.overviewSections}>
|
|
<div className={css.overviewSections}>
|
|
|
- {isMarkdownRecord(selected)
|
|
|
|
|
|
|
+ {selectedProgram !== undefined
|
|
|
? (
|
|
? (
|
|
|
<>
|
|
<>
|
|
|
- <OverviewSection label={t('tab.preview')} onOpen={() => { activateTab('rendered') }}>
|
|
|
|
|
- <MarkdownRecordContent
|
|
|
|
|
- record={selected}
|
|
|
|
|
- renderImages={renderImages}
|
|
|
|
|
- rendered
|
|
|
|
|
- preview
|
|
|
|
|
- thinkingExpanded={thinkingExpanded}
|
|
|
|
|
- onThinkingExpandedChange={setThinkingExpanded}
|
|
|
|
|
- onOpenCall={openCallSummary}
|
|
|
|
|
- t={t}
|
|
|
|
|
- />
|
|
|
|
|
- </OverviewSection>
|
|
|
|
|
|
|
+ <ProgramInput key={`preview:${selectedRecordId}`} program={selectedProgram}
|
|
|
|
|
+ initialWrapped={codeWrappingOnOpen}
|
|
|
|
|
+ stringWrapping={stringWrapping} onOpen={() => { activateTab('input') }} t={t} />
|
|
|
|
|
+ <ProgramOutput record={selected} stringWrapping={stringWrapping}
|
|
|
|
|
+ onOpen={() => { activateTab('output') }} t={t} />
|
|
|
</>
|
|
</>
|
|
|
)
|
|
)
|
|
|
- : (
|
|
|
|
|
- <>
|
|
|
|
|
- {selected.cell.inputDetail && (
|
|
|
|
|
- <OverviewSection label={t('tab.payload')} onOpen={() => { activateTab('input') }}>
|
|
|
|
|
- <RecordPayload record={selected} direction="input" preview renderImages={renderImages} t={t} />
|
|
|
|
|
|
|
+ : isMarkdownRecord(selected)
|
|
|
|
|
+ ? (
|
|
|
|
|
+ <>
|
|
|
|
|
+ <OverviewSection label={t('tab.preview')} onOpen={() => { activateTab('rendered') }}>
|
|
|
|
|
+ <MarkdownRecordContent
|
|
|
|
|
+ record={selected}
|
|
|
|
|
+ renderImages={renderImages}
|
|
|
|
|
+ rendered
|
|
|
|
|
+ preview
|
|
|
|
|
+ thinkingExpanded={thinkingExpanded}
|
|
|
|
|
+ onThinkingExpandedChange={setThinkingExpanded}
|
|
|
|
|
+ onOpenCall={openCallSummary}
|
|
|
|
|
+ t={t}
|
|
|
|
|
+ />
|
|
|
</OverviewSection>
|
|
</OverviewSection>
|
|
|
- )}
|
|
|
|
|
- {selected.cell.outputDetail && (
|
|
|
|
|
- <OverviewSection label={t('tab.result')} onOpen={() => { activateTab('output') }}>
|
|
|
|
|
- <RecordPayload record={selected} direction="output" preview renderImages={renderImages} t={t} />
|
|
|
|
|
|
|
+ </>
|
|
|
|
|
+ )
|
|
|
|
|
+ : (
|
|
|
|
|
+ <>
|
|
|
|
|
+ {selected.cell.inputDetail && (
|
|
|
|
|
+ <OverviewSection label={t('tab.payload')} onOpen={() => { activateTab('input') }}>
|
|
|
|
|
+ <RecordPayload record={selected} direction="input" preview renderImages={renderImages} stringWrapping={stringWrapping} t={t} />
|
|
|
|
|
+ </OverviewSection>
|
|
|
|
|
+ )}
|
|
|
|
|
+ {selected.cell.outputDetail && (
|
|
|
|
|
+ <OverviewSection label={t('tab.result')} onOpen={() => { activateTab('output') }}>
|
|
|
|
|
+ <RecordPayload record={selected} direction="output" preview renderImages={renderImages} stringWrapping={stringWrapping} t={t} />
|
|
|
|
|
+ </OverviewSection>
|
|
|
|
|
+ )}
|
|
|
|
|
+ <OverviewSection label={t('tab.schema')} onOpen={() => { activateTab('schema') }}>
|
|
|
|
|
+ <RecordSchema record={selected} preview stringWrapping={stringWrapping} t={t} />
|
|
|
</OverviewSection>
|
|
</OverviewSection>
|
|
|
- )}
|
|
|
|
|
- <OverviewSection label={t('tab.schema')} onOpen={() => { activateTab('schema') }}>
|
|
|
|
|
- <RecordSchema record={selected} preview t={t} />
|
|
|
|
|
- </OverviewSection>
|
|
|
|
|
- </>
|
|
|
|
|
- )}
|
|
|
|
|
|
|
+ </>
|
|
|
|
|
+ )}
|
|
|
{selectedAssistantRequestTarget !== undefined && (
|
|
{selectedAssistantRequestTarget !== undefined && (
|
|
|
<OverviewSection
|
|
<OverviewSection
|
|
|
label={t('timing.request')}
|
|
label={t('timing.request')}
|
|
@@ -3152,12 +3399,12 @@ export function TrajectoryTable({
|
|
|
selectRequest(selectedAssistantRequestTarget, 'timing')
|
|
selectRequest(selectedAssistantRequestTarget, 'timing')
|
|
|
}}
|
|
}}
|
|
|
>
|
|
>
|
|
|
- <RecordTiming record={selected} t={t} />
|
|
|
|
|
|
|
+ <RecordTiming record={selected} preview t={t} />
|
|
|
</OverviewSection>
|
|
</OverviewSection>
|
|
|
)}
|
|
)}
|
|
|
{(selected.cell.kind === 'tool' || selected.cell.kind === 'subtool') && (
|
|
{(selected.cell.kind === 'tool' || selected.cell.kind === 'subtool') && (
|
|
|
<OverviewSection label={t('tab.timing')} onOpen={() => { activateTab('timing') }}>
|
|
<OverviewSection label={t('tab.timing')} onOpen={() => { activateTab('timing') }}>
|
|
|
- <RecordTiming record={selected} t={t} />
|
|
|
|
|
|
|
+ <RecordTiming record={selected} preview t={t} />
|
|
|
</OverviewSection>
|
|
</OverviewSection>
|
|
|
)}
|
|
)}
|
|
|
</div>
|
|
</div>
|
|
@@ -3186,16 +3433,22 @@ export function TrajectoryTable({
|
|
|
/>
|
|
/>
|
|
|
)}
|
|
)}
|
|
|
{!promptSelected && selected !== undefined && activeTab === 'source' && (
|
|
{!promptSelected && selected !== undefined && activeTab === 'source' && (
|
|
|
- <MessageSource record={selected} t={t} />
|
|
|
|
|
|
|
+ <MessageSource record={selected} stringWrapping={stringWrapping} t={t} />
|
|
|
)}
|
|
)}
|
|
|
{!promptSelected && selected !== undefined && activeTab === 'input' && (
|
|
{!promptSelected && selected !== undefined && activeTab === 'input' && (
|
|
|
- <RecordPayload record={selected} direction="input" renderImages={renderImages} t={t} />
|
|
|
|
|
|
|
+ selectedProgram === undefined
|
|
|
|
|
+ ? <RecordPayload record={selected} direction="input" renderImages={renderImages} stringWrapping={stringWrapping} t={t} />
|
|
|
|
|
+ : <ProgramInput key={`input:${selectedRecordId}`} program={selectedProgram}
|
|
|
|
|
+ initialWrapped={codeWrappingOnOpen}
|
|
|
|
|
+ stringWrapping={stringWrapping} t={t} />
|
|
|
)}
|
|
)}
|
|
|
{!promptSelected && selected !== undefined && activeTab === 'output' && (
|
|
{!promptSelected && selected !== undefined && activeTab === 'output' && (
|
|
|
- <RecordPayload record={selected} direction="output" renderImages={renderImages} t={t} />
|
|
|
|
|
|
|
+ selectedProgram === undefined
|
|
|
|
|
+ ? <RecordPayload record={selected} direction="output" renderImages={renderImages} stringWrapping={stringWrapping} t={t} />
|
|
|
|
|
+ : <ProgramOutput record={selected} stringWrapping={stringWrapping} t={t} />
|
|
|
)}
|
|
)}
|
|
|
{!promptSelected && selected !== undefined && activeTab === 'schema' && (
|
|
{!promptSelected && selected !== undefined && activeTab === 'schema' && (
|
|
|
- <RecordSchema record={selected} t={t} />
|
|
|
|
|
|
|
+ <RecordSchema record={selected} stringWrapping={stringWrapping} t={t} />
|
|
|
)}
|
|
)}
|
|
|
{!promptSelected && selected !== undefined && activeTab === 'timing' && (
|
|
{!promptSelected && selected !== undefined && activeTab === 'timing' && (
|
|
|
<RecordTiming record={selected} t={t} />
|
|
<RecordTiming record={selected} t={t} />
|