feat(app): align execute tool with shell treatment (#44642)

This commit is contained in:
Luke Parker 2026-08-24 19:20:56 +10:00 committed by GitHub
parent 0a410e404b
commit 279062d3c9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 40 additions and 9 deletions

View file

@ -530,6 +530,26 @@ export const expandedShellDocument = document([
}),
] satisfies SessionMessageInfo[])
export const executeCodeDocument = document([
user("msg_user_execute", "Verify the Code Mode runtime responds.", 52_100),
assistant({
id: "msg_assistant_execute",
offset: 52_200,
completed: 52_900,
content: [
completedTool({
id: "tool_execute_code",
name: "execute",
offset: 52_300,
args: {
code: 'const greeting = "Code Mode execute completed"\nreturn { greeting, timestamp: new Date().toISOString() }',
},
output: '{\n "greeting": "Code Mode execute completed",\n "timestamp": "2026-08-17T09:01:43.590Z"\n}',
}),
],
}),
] satisfies SessionMessageInfo[])
export const terminalFailedDocument = document([
user("msg_user_terminal_failed", "Run the focused Session UI tests.", 53_000),
assistant({

View file

@ -1,5 +1,6 @@
import { CurrentSessionTimelineStory } from "../storybook/current-session-story"
import {
executeCodeDocument,
expandedShellDocument,
recoveryDocument,
standaloneShellCompletedDocument,
@ -85,6 +86,18 @@ export const ExpandedShell = {
),
}
export const ExecuteCode = {
render: () => (
<CurrentSessionTimelineStory
title="Execute code"
description="A Code Mode execution shares the shell treatment: the code and its result split into a two-tone card."
document={executeCodeDocument}
width="786px"
shellToolDefaultOpen
/>
),
}
export const TestFailed = {
render: () => (
<CurrentSessionTimelineStory

View file

@ -1255,34 +1255,32 @@ ToolRegistry.register({
const i18n = useI18n()
const pending = () => props.status === "streaming" || props.status === "running"
const code = createMemo(() => (typeof props.input.code === "string" ? props.input.code : ""))
const text = createMemo(() => {
const output = stripAnsi(props.output ?? "").replace(/\r\n?/g, "\n")
return `${code()}${output ? "\n\n" + output : ""}`
})
const output = createMemo(() => stripAnsi(props.output ?? "").replace(/\r\n?/g, "\n"))
const sawPending = pending()
return (
<BasicTool
{...props}
icon="console"
rail={false}
compact
allowOpenWhilePending
trigger={(open) => (
<div data-slot="basic-tool-tool-info-structured">
<span data-slot="basic-tool-tool-indicator">
<Icon name="console" size="small" />
</span>
<div data-slot="basic-tool-tool-info-main">
<span data-slot="basic-tool-tool-title">
<TextShimmer text={i18n.t("ui.tool.execute")} active={pending()} />
</span>
<Show when={!open() && code()}>
<ShellSubmessage text={code()} animate={sawPending} />
<ShellSubmessage text={code().split("\n")[0]} animate={sawPending} />
</Show>
</div>
</div>
)}
>
<ConsoleOutput copy={text()}>{text()}</ConsoleOutput>
<ConsoleOutput copy={code()} variant="shell">
<span data-slot="bash-command">{code()}</span>
<Show when={output()}>{(value) => <span data-slot="bash-result">{value()}</span>}</Show>
</ConsoleOutput>
</BasicTool>
)
},