summaryrefslogtreecommitdiffhomepage
path: root/packages/ui/src/components/message-part.tsx
diff options
context:
space:
mode:
authorAdam <[email protected]>2026-03-12 16:25:36 -0500
committerAdam <[email protected]>2026-03-12 16:25:49 -0500
commit9d3c42c8c49ec56ee890dc2af9c47f19494999fc (patch)
treea71cda6b9c27e7cb426bfd78eead45a2fa54afae /packages/ui/src/components/message-part.tsx
parentf2cad046e6c38885b454d01cb28888152a54b375 (diff)
downloadopencode-9d3c42c8c49ec56ee890dc2af9c47f19494999fc.tar.gz
opencode-9d3c42c8c49ec56ee890dc2af9c47f19494999fc.zip
fix(app): task error state
Diffstat (limited to 'packages/ui/src/components/message-part.tsx')
-rw-r--r--packages/ui/src/components/message-part.tsx62
1 files changed, 43 insertions, 19 deletions
diff --git a/packages/ui/src/components/message-part.tsx b/packages/ui/src/components/message-part.tsx
index 5a0f022ea..500c73c5e 100644
--- a/packages/ui/src/components/message-part.tsx
+++ b/packages/ui/src/components/message-part.tsx
@@ -344,6 +344,17 @@ function urls(text: string | undefined) {
})
}
+function sessionLink(id: string | undefined, path: string, href?: (id: string) => string | undefined) {
+ if (!id) return
+
+ const direct = href?.(id)
+ if (direct) return direct
+
+ const idx = path.indexOf("/session")
+ if (idx === -1) return
+ return `${path.slice(0, idx)}/session/${id}`
+}
+
const CONTEXT_GROUP_TOOLS = new Set(["read", "glob", "grep", "list"])
const HIDDEN_TOOLS = new Set(["todowrite", "todoread"])
@@ -1215,6 +1226,7 @@ function ToolFileAccordion(props: { path: string; actions?: JSX.Element; childre
}
PART_MAPPING["tool"] = function ToolPartDisplay(props) {
+ const data = useData()
const i18n = useI18n()
const part = () => props.part as ToolPart
if (part().tool === "todowrite" || part().tool === "todoread") return null
@@ -1229,6 +1241,21 @@ PART_MAPPING["tool"] = function ToolPartDisplay(props) {
const input = () => part().state?.input ?? emptyInput
// @ts-expect-error
const partMetadata = () => part().state?.metadata ?? emptyMetadata
+ const taskId = createMemo(() => {
+ if (part().tool !== "task") return
+ const value = partMetadata().sessionId
+ if (typeof value === "string" && value) return value
+ })
+ const taskHref = createMemo(() => {
+ if (part().tool !== "task") return
+ return sessionLink(taskId(), useLocation().pathname, data.sessionHref)
+ })
+ const taskSubtitle = createMemo(() => {
+ if (part().tool !== "task") return undefined
+ const value = input().description
+ if (typeof value === "string" && value) return value
+ return taskId()
+ })
const render = createMemo(() => ToolRegistry.render(part().tool) ?? GenericTool)
@@ -1248,7 +1275,15 @@ PART_MAPPING["tool"] = function ToolPartDisplay(props) {
</div>
)
}
- return <ToolErrorCard tool={part().tool} error={error()} defaultOpen={props.defaultOpen} />
+ return (
+ <ToolErrorCard
+ tool={part().tool}
+ error={error()}
+ defaultOpen={props.defaultOpen}
+ subtitle={taskSubtitle()}
+ href={taskHref()}
+ />
+ )
}}
</Match>
<Match when={true}>
@@ -1625,25 +1660,14 @@ ToolRegistry.register({
return raw[0]!.toUpperCase() + raw.slice(1)
})
const title = createMemo(() => agentTitle(i18n, type()))
- const description = createMemo(() => {
+ const subtitle = createMemo(() => {
const value = props.input.description
- if (typeof value === "string") return value
- return undefined
+ if (typeof value === "string" && value) return value
+ return childSessionId()
})
const running = createMemo(() => props.status === "pending" || props.status === "running")
- const href = createMemo(() => {
- const sessionId = childSessionId()
- if (!sessionId) return
-
- const direct = data.sessionHref?.(sessionId)
- if (direct) return direct
-
- const path = location.pathname
- const idx = path.indexOf("/session")
- if (idx === -1) return
- return `${path.slice(0, idx)}/session/${sessionId}`
- })
+ const href = createMemo(() => sessionLink(childSessionId(), location.pathname, data.sessionHref))
const titleContent = () => <TextShimmer text={title()} active={running()} />
@@ -1653,7 +1677,7 @@ ToolRegistry.register({
<span data-slot="basic-tool-tool-title" class="capitalize agent-title">
{titleContent()}
</span>
- <Show when={description()}>
+ <Show when={subtitle()}>
<Switch>
<Match when={href()}>
<a
@@ -1662,11 +1686,11 @@ ToolRegistry.register({
href={href()!}
onClick={(e) => e.stopPropagation()}
>
- {description()}
+ {subtitle()}
</a>
</Match>
<Match when={true}>
- <span data-slot="basic-tool-tool-subtitle">{description()}</span>
+ <span data-slot="basic-tool-tool-subtitle">{subtitle()}</span>
</Match>
</Switch>
</Show>