fix(mobile): keep a blank tool argument out of the run header (STA-3333)

Skipping a present-but-blank primary key let `briefToolArg` fall through
to the raw JSON preview, so a run header read `Bash {"command":""}` where
it used to read `Bash`. Also state the search-path trade-off honestly:
suppressing the link costs a file-scoped search its tap target.
This commit is contained in:
Brennan Benson
2026-08-04 03:55:17 -07:00
parent 6b43b51711
commit 6fd7dd552a
2 changed files with 20 additions and 3 deletions
@@ -162,6 +162,16 @@ describe('briefToolArg', () => {
it('falls back to the command preview when no path is present', () => {
expect(briefToolArg({ command: 'git status --short' })).toBe('git status --short')
})
it('keeps a blank primary argument out of the run header', () => {
// Skipping a blank key must not fall through to raw JSON — the row would
// read `Bash {"command":""}` where it used to read `Bash`.
expect(briefToolArg({ command: '' })).toBe('')
expect(briefToolArg({ cmd: ' ' })).toBe('')
expect(briefToolArg({ cmd: '', file_path: '' })).toBe('')
const blocks: NativeChatBlock[] = [{ type: 'tool-call', name: 'Bash', input: { command: '' } }]
expect(summarizeToolRun(blocks)).toBe('Bash')
})
})
describe('summarizeToolRun', () => {
+10 -3
View File
@@ -74,8 +74,9 @@ export function toolFilePath(input: unknown): string | null {
return null
}
const value = normalized as Record<string, unknown>
// A search call's `path` is the directory it scanned, not a file it opened —
// taking it would drop the pattern from the label and offer a link to a folder.
// A search call's `path` is usually the directory it scanned, so taking it as a
// target would label the row with the scan root and link to a folder. Costs the
// link on a file-scoped search; a dead link on every other search is worse.
const directory = isSearchToolInput(value) ? undefined : value.path
const path = value.file_path ?? value.filePath ?? directory ?? value.notebook_path
return typeof path === 'string' && path.length > 0 ? path : null
@@ -89,10 +90,16 @@ export function briefToolArg(input: unknown): string {
const parts = path.split(/[\\/]/).filter(Boolean)
return parts.at(-1) ?? path
}
const command = firstPrimaryToolArg(normalized as Record<string, unknown>, BRIEF_ARG_KEYS)
const value = normalized as Record<string, unknown>
const command = firstPrimaryToolArg(value, BRIEF_ARG_KEYS)
if (command) {
return command.slice(0, 28)
}
// A blank primary key means the call has no brief argument; falling through
// would stand its raw JSON in for one in the run header.
if (BRIEF_ARG_KEYS.some((key) => Object.prototype.hasOwnProperty.call(value, key))) {
return ''
}
}
return summarizeToolInput(normalized).slice(0, 28)
}