fix(mobile): expand JSON-string tool details

This commit is contained in:
Brennan Benson
2026-08-03 19:51:22 -07:00
parent 693c0b94a7
commit 28d52a0bd0
4 changed files with 37 additions and 2 deletions
@@ -1,5 +1,5 @@
import { createElement } from 'react'
import { act, create, type ReactTestRenderer } from 'react-test-renderer'
import { act, create, type ReactTestInstance, type ReactTestRenderer } from 'react-test-renderer'
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'
import type { NativeChatMessage } from '../../../src/shared/native-chat-types'
import { MAX_TOOL_RESULT_CHARS } from './mobile-native-chat-message-styles'
@@ -110,4 +110,32 @@ describe('MobileNativeChatMessage', () => {
expect(detail).toHaveLength(MAX_TOOL_RESULT_CHARS + 1)
expect(detail?.endsWith('…')).toBe(true)
})
it('expands formatted detail for a pending JSON-string tool input', () => {
const tree = render({
id: 'a1',
role: 'assistant',
blocks: [
{
type: 'tool-call',
name: 'CustomTool',
input: '{"cmd":"git status","description":"Inspect changes"}'
}
],
timestamp: null,
source: 'transcript'
})
const textIn = (node: ReactTestInstance): string[] =>
node.findAllByType('Text' as never).map((text) => String(text.children.join('')))
const pressableWith = (label: string) =>
tree.root.findAllByType('Pressable' as never).find((node) => textIn(node).includes(label))!
act(() => pressableWith('1×').props.onPress())
expect(textIn(tree.root).some((text) => text.startsWith('{\n'))).toBe(false)
act(() => pressableWith('CustomTool').props.onPress())
expect(textIn(tree.root)).toContain(
'{\n "cmd": "git status",\n "description": "Inspect changes"\n}'
)
})
})
@@ -19,6 +19,7 @@ import { nativeChatMessageText } from './mobile-native-chat-message-text'
import {
describeToolInput,
formatToolInput,
isStructuredToolInput,
summarizeToolRun,
toolFilePath
} from './mobile-native-chat-tool-summary'
@@ -109,7 +110,7 @@ function ToolLine({
callDiff !== null ||
result !== undefined ||
preview.length > 40 ||
(call !== undefined && call.input !== null && typeof call.input === 'object')
(call !== undefined && isStructuredToolInput(call.input))
// A tool that targets a file (Read/Edit/Write…) renders its preview as a
// tappable link that opens the file, independent of the line's expand tap.
const filePath = call ? toolFilePath(call.input) : null
@@ -3,6 +3,7 @@ export {
countToolCalls,
describeToolInput,
formatToolInput,
isStructuredToolInput,
summarizeToolInput,
summarizeToolRun,
toolFilePath
+5
View File
@@ -57,6 +57,11 @@ export function formatToolInput(input: unknown): string {
}
}
export function isStructuredToolInput(input: unknown): boolean {
const normalized = normalizeToolInput(input)
return normalized !== null && typeof normalized === 'object'
}
export function toolFilePath(input: unknown): string | null {
const normalized = normalizeToolInput(input)
if (!normalized || typeof normalized !== 'object') {