fix(mobile): don't offer an expander whose detail repeats the row (STA-3333)

An empty tool input formats back to the row label verbatim, so `{}` and `[]`
advertised an expander and then re-showed the label — the same repeat-the-JSON
problem this change set out to remove. Gate `isStructuredToolInput` on the
collection actually having contents; the lazy detail path is untouched.

Also pins the overlong-path test to the path itself: asserting only length<=80
plus a `…` passed just as well with path labelling deleted.
This commit is contained in:
Brennan Benson
2026-08-04 02:36:16 -07:00
parent 8ebc662530
commit 27fe90a6f2
2 changed files with 24 additions and 3 deletions
+18 -2
View File
@@ -41,8 +41,13 @@ describe('describeToolInput', () => {
it('truncates an overlong path like any other preview', () => {
const path = `/very/${'long/'.repeat(30)}file.ts`
expect(describeToolInput({ file_path: path }).length).toBeLessThanOrEqual(80)
expect(describeToolInput({ file_path: path })).toContain('…')
const label = describeToolInput({ file_path: path })
expect(label.length).toBeLessThanOrEqual(80)
expect(label).toContain('…')
// A bounded JSON preview also satisfies the two assertions above, so pin the
// label to the path itself or this passes with path-labelling deleted.
expect(label).not.toContain('file_path')
expect(label.endsWith('/file.ts')).toBe(true)
})
it('keeps the filename when trimming an overlong path', () => {
@@ -115,6 +120,17 @@ describe('Codex JSON-string tool arguments', () => {
})
})
describe('isStructuredToolInput', () => {
it('does not offer an expander whose detail would repeat the row label', () => {
// `{}` formats back to `{}` — the label itself.
expect(isStructuredToolInput({})).toBe(false)
expect(isStructuredToolInput([])).toBe(false)
expect(isStructuredToolInput('{}')).toBe(false)
expect(isStructuredToolInput({ command: 'ls' })).toBe(true)
expect(isStructuredToolInput([1])).toBe(true)
})
})
describe('summarizeToolInput bounded preview', () => {
it('collapses depth beyond the bound instead of serializing the whole tree', () => {
const deep = { a: { b: { c: { d: 'buried' } } } }
+6 -1
View File
@@ -60,7 +60,12 @@ export function formatToolInput(input: unknown): string {
* the row label — i.e. whether expanding the row is worth offering. */
export function isStructuredToolInput(input: unknown): boolean {
const normalized = normalizeToolInput(input)
return normalized !== null && typeof normalized === 'object'
if (normalized === null || typeof normalized !== 'object') {
return false
}
// An empty object formats back to the row label verbatim, so offering the
// expander would promise detail and then repeat the row.
return Array.isArray(normalized) ? normalized.length > 0 : Object.keys(normalized).length > 0
}
export function toolFilePath(input: unknown): string | null {