fix(desktop): stop the tool row repeating its command three times

The expanded terminal row printed the same string as the title, as the
`$` transcript, and again as detail. shellCommand preferred the
backend's display preview over the real `command` arg, so the transcript
showed a summary of what ran rather than what ran; and a terminal call
with no output fell through to the generic fallback, which echoes
args.context under a transcript already showing it.
This commit is contained in:
Brooklyn Nicholson 2026-07-26 16:03:49 -05:00
parent f0031abc39
commit ec6719b04e
2 changed files with 35 additions and 1 deletions

View file

@ -340,6 +340,28 @@ describe('buildToolView title actions', () => {
expect(view.titleAction).toEqual({ prefix: '', text: 'Running', suffix: ' pnpm run lint' })
})
it('never stutters the verb or echoes the command when the backend context is a phrased label', () => {
// Older backends stamped tool.start with a *phrased* label
// ("Running sleep 70 + 2 commands") rather than a raw arg preview, and the
// desktop merges that into args.context. The row must still prepend its own
// verb exactly once, show the real command in the `$` transcript, and not
// repeat either string as detail.
const command = 'sleep 70; echo "a"; echo "b"'
const view = buildToolView(
part({
args: { command, context: 'Running sleep 70 + 2 commands' },
result: { exit_code: 0 },
toolName: 'terminal'
}),
''
)
expect(view.title).toBe('Ran sleep 70 + 2 commands')
expect(view.terminalCommand).toBe(command)
expect(view.detail).toBe('')
})
it('uses the runtime locale for title text and action placement', () => {
setRuntimeI18nLocale('ja')

View file

@ -128,9 +128,14 @@ function readFileDisplayTarget(args: Record<string, unknown>, result: Record<str
return [fileEditBasename(path), lineLabel].filter(Boolean).join(' ')
}
// The real command, preferring the actual argument over the backend's
// display preview. `context` is a *summarized* preview ("sleep 70 + 2
// commands") the gateway sends on tool.start before real args arrive — fine
// as a placeholder for the live title, wrong for the `$` transcript, which
// must show what actually ran.
function shellCommand(args: Record<string, unknown>): string {
return (
firstStringField(args, ['context', 'preview']) || firstStringField(args, ['command', 'code']) || contextValue(args)
firstStringField(args, ['command', 'code']) || firstStringField(args, ['context', 'preview']) || contextValue(args)
)
}
@ -1079,6 +1084,13 @@ function toolDetailText(
if (output || lines) {
return [output, lines].filter(Boolean).join('\n')
}
// A terminal row with no output already shows its command in the `$`
// transcript above; the generic fallback would print the same string a
// second time. `execute_code` has no transcript, so it keeps the fallback.
if (part.toolName === 'terminal') {
return ''
}
}
if (part.toolName === 'web_extract') {