Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
countDiffLineStats,
inlineDiffFromResult,
MAX_TOOL_RENDER_CHARS,
prettyJson,
type ToolPart
} from './fallback-model'

Expand Down Expand Up @@ -342,15 +343,16 @@ describe('clampForDisplay', () => {
})

// A large tool result (e.g. a 100KB read_file during a `/learn` run) must not
// be serialized into the rendered rawResult at full size — that JSON.stringify
// payload is what floods the renderer when many rows stack up.
describe('buildToolView caps serialized result size', () => {
it('clamps rawResult for an oversized result', () => {
// be serialized at full size — that JSON.stringify payload is what floods the
// renderer. buildToolView no longer prettyJson's every result eagerly; the
// web_search drilldown serializes lazily via prettyJson, which clamps.
describe('prettyJson caps serialized result size', () => {
it('clamps an oversized result', () => {
const huge = 'y'.repeat(MAX_TOOL_RENDER_CHARS * 3)
const view = buildToolView(part({ result: { content: huge }, toolName: 'read_file' }), '')
const out = prettyJson({ content: huge })

expect(view.rawResult.length).toBeLessThanOrEqual(MAX_TOOL_RENDER_CHARS + 200)
expect(view.rawResult).toContain('truncated')
expect(out.length).toBeLessThanOrEqual(MAX_TOOL_RENDER_CHARS + 200)
expect(out).toContain('truncated')
})
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
isRecord,
numberValue,
parseMaybeObject,
prettyJson,
unwrapToolPayload
} from './format'
import { findFirstUrl, hostnameOf, looksLikePath, looksLikeUrl } from './targets'
Expand Down Expand Up @@ -1409,8 +1408,6 @@ export function buildToolView(part: ToolPart, inlineDiff: string): ToolView {
imageUrl: toolImageUrl(argsRecord, resultRecord),
inlineDiff,
previewTarget: toolPreviewTarget(part.toolName, argsRecord, resultRecord),
rawArgs: prettyJson(part.args),
rawResult: prettyJson(part.result),
rendersAnsi: rendersAnsi || undefined,
searchHits: searchHits?.length ? searchHits : undefined,
stderr: hasSplitStreams ? stderrRaw || undefined : undefined,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,6 @@ export interface ToolView {
imageUrl?: string
inlineDiff: string
previewTarget?: string
rawArgs: string
rawResult: string
/** Set for tools whose output naturally contains ANSI escape codes
* (terminal/execute_code) so the renderer knows to run them through
* the ANSI parser instead of printing them as literals. */
Expand Down
15 changes: 10 additions & 5 deletions apps/desktop/src/components/assistant-ui/tool/fallback.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ import {
type ToolStatus,
type ToolTitleAction
} from './fallback-model'
import { prettyJson } from './fallback-model/format'

// `true` when a ToolEntry is rendered inside an embedding wrapper that owns
// the per-row chrome (timer / preview). The flat ToolGroupSlot sets this
Expand Down Expand Up @@ -367,11 +368,15 @@ function ToolEntry({ part }: ToolEntryProps) {
const hasSearchHits = Boolean(view.searchHits?.length)
const searchResultsLabel = part.toolName === 'web_search' ? 'Search results' : view.detailLabel

// Only web_search renders the raw JSON drilldown, so serialize the result
// lazily here instead of prettyJson-ing every tool's result in buildToolView.
const rawResult = useMemo(
() => (part.toolName === 'web_search' && toolViewMode !== 'technical' ? prettyJson(part.result) : ''),
[part.toolName, part.result, toolViewMode]
)

const showRawSearchDrilldown =
part.toolName === 'web_search' &&
part.result !== undefined &&
toolViewMode !== 'technical' &&
Boolean(view.rawResult.trim())
part.toolName === 'web_search' && part.result !== undefined && toolViewMode !== 'technical' && Boolean(rawResult.trim())

const hasExpandableContent = Boolean(
view.imageUrl || view.inlineDiff || showDetail || hasSearchHits || toolViewMode === 'technical'
Expand Down Expand Up @@ -587,7 +592,7 @@ function ToolEntry({ part }: ToolEntryProps) {
<details className="max-w-full">
<summary className={cn(TOOL_SECTION_LABEL_CLASS, 'mb-0')}>{copy.rawResponse}</summary>
<pre className={cn(TOOL_SECTION_PRE_CLASS, 'mt-1 whitespace-pre-wrap wrap-anywhere')}>
{view.rawResult}
{rawResult}
</pre>
</details>
)}
Expand Down
Loading