fix(app): task tool rendering

This commit is contained in:
Adam
2026-02-10 15:28:42 -06:00
parent 21475a1dfd
commit 50f3e74d05
3 changed files with 87 additions and 32 deletions

View File

@@ -54,6 +54,13 @@ export default function Layout(props: ParentProps) {
navigate(`/${params.dir}/session/${sessionID}`) navigate(`/${params.dir}/session/${sessionID}`)
} }
const sessionHref = (sessionID: string) => {
if (params.dir) return `/${params.dir}/session/${sessionID}`
return `/session/${sessionID}`
}
const syncSession = (sessionID: string) => sync.session.sync(sessionID)
return ( return (
<DataProvider <DataProvider
data={sync.data} data={sync.data}
@@ -62,6 +69,8 @@ export default function Layout(props: ParentProps) {
onQuestionReply={replyToQuestion} onQuestionReply={replyToQuestion}
onQuestionReject={rejectQuestion} onQuestionReject={rejectQuestion}
onNavigateToSession={navigateToSession} onNavigateToSession={navigateToSession}
onSessionHref={sessionHref}
onSyncSession={syncSession}
> >
<LocalProvider>{props.children}</LocalProvider> <LocalProvider>{props.children}</LocalProvider>
</DataProvider> </DataProvider>

View File

@@ -877,6 +877,74 @@ ToolRegistry.register({
const data = useData() const data = useData()
const i18n = useI18n() const i18n = useI18n()
const childSessionId = () => props.metadata.sessionId as string | undefined const childSessionId = () => props.metadata.sessionId as string | undefined
const href = createMemo(() => {
const sessionId = childSessionId()
if (!sessionId) return
const direct = data.sessionHref?.(sessionId)
if (direct) return direct
if (typeof window === "undefined") return
const path = window.location.pathname
const idx = path.indexOf("/session")
if (idx === -1) return
return `${path.slice(0, idx)}/session/${sessionId}`
})
createEffect(() => {
const sessionId = childSessionId()
if (!sessionId) return
const sync = data.syncSession
if (!sync) return
Promise.resolve(sync(sessionId)).catch(() => undefined)
})
const handleLinkClick = (e: MouseEvent) => {
const sessionId = childSessionId()
const url = href()
if (!sessionId || !url) return
e.stopPropagation()
if (e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return
const nav = data.navigateToSession
if (!nav || typeof window === "undefined") return
e.preventDefault()
const before = window.location.pathname + window.location.search + window.location.hash
nav(sessionId)
setTimeout(() => {
const after = window.location.pathname + window.location.search + window.location.hash
if (after === before) window.location.assign(url)
}, 50)
}
const trigger = () => (
<div data-slot="basic-tool-tool-info-structured">
<div data-slot="basic-tool-tool-info-main">
<span data-slot="basic-tool-tool-title" class="capitalize">
{i18n.t("ui.tool.agent", { type: props.input.subagent_type || props.tool })}
</span>
<Show when={props.input.description}>
<Switch>
<Match when={href()}>
{(url) => (
<a data-slot="basic-tool-tool-subtitle" class="clickable" href={url()} onClick={handleLinkClick}>
{props.input.description}
</a>
)}
</Match>
<Match when={true}>
<span data-slot="basic-tool-tool-subtitle">{props.input.description}</span>
</Match>
</Switch>
</Show>
</div>
</div>
)
const childToolParts = createMemo(() => { const childToolParts = createMemo(() => {
const sessionId = childSessionId() const sessionId = childSessionId()
if (!sessionId) return [] if (!sessionId) return []
@@ -924,13 +992,6 @@ ToolRegistry.register({
}) })
} }
const handleSubtitleClick = () => {
const sessionId = childSessionId()
if (sessionId && data.navigateToSession) {
data.navigateToSession(sessionId)
}
}
const renderChildToolPart = () => { const renderChildToolPart = () => {
const toolData = childToolPart() const toolData = childToolPart()
if (!toolData) return null if (!toolData) return null
@@ -958,21 +1019,7 @@ ToolRegistry.register({
<Switch> <Switch>
<Match when={childPermission()}> <Match when={childPermission()}>
<> <>
<Show <Show when={childToolPart()} fallback={<BasicTool icon="task" defaultOpen={true} trigger={trigger()} />}>
when={childToolPart()}
fallback={
<BasicTool
icon="task"
defaultOpen={true}
trigger={{
title: i18n.t("ui.tool.agent", { type: props.input.subagent_type || props.tool }),
titleClass: "capitalize",
subtitle: props.input.description,
}}
onSubtitleClick={handleSubtitleClick}
/>
}
>
{renderChildToolPart()} {renderChildToolPart()}
</Show> </Show>
<div data-component="permission-prompt"> <div data-component="permission-prompt">
@@ -991,16 +1038,7 @@ ToolRegistry.register({
</> </>
</Match> </Match>
<Match when={true}> <Match when={true}>
<BasicTool <BasicTool icon="task" defaultOpen={true} trigger={trigger()}>
icon="task"
defaultOpen={true}
trigger={{
title: i18n.t("ui.tool.agent", { type: props.input.subagent_type || props.tool }),
titleClass: "capitalize",
subtitle: props.input.description,
}}
onSubtitleClick={handleSubtitleClick}
>
<div <div
ref={autoScroll.scrollRef} ref={autoScroll.scrollRef}
onScroll={autoScroll.handleScroll} onScroll={autoScroll.handleScroll}

View File

@@ -48,6 +48,10 @@ export type QuestionRejectFn = (input: { requestID: string }) => void
export type NavigateToSessionFn = (sessionID: string) => void export type NavigateToSessionFn = (sessionID: string) => void
export type SessionHrefFn = (sessionID: string) => string
export type SyncSessionFn = (sessionID: string) => void | Promise<void>
export const { use: useData, provider: DataProvider } = createSimpleContext({ export const { use: useData, provider: DataProvider } = createSimpleContext({
name: "Data", name: "Data",
init: (props: { init: (props: {
@@ -57,6 +61,8 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
onQuestionReply?: QuestionReplyFn onQuestionReply?: QuestionReplyFn
onQuestionReject?: QuestionRejectFn onQuestionReject?: QuestionRejectFn
onNavigateToSession?: NavigateToSessionFn onNavigateToSession?: NavigateToSessionFn
onSessionHref?: SessionHrefFn
onSyncSession?: SyncSessionFn
}) => { }) => {
return { return {
get store() { get store() {
@@ -69,6 +75,8 @@ export const { use: useData, provider: DataProvider } = createSimpleContext({
replyToQuestion: props.onQuestionReply, replyToQuestion: props.onQuestionReply,
rejectQuestion: props.onQuestionReject, rejectQuestion: props.onQuestionReject,
navigateToSession: props.onNavigateToSession, navigateToSession: props.onNavigateToSession,
sessionHref: props.onSessionHref,
syncSession: props.onSyncSession,
} }
}, },
}) })