-
scrollHelpers.handleScroll(event as Event & { currentTarget: HTMLDivElement }) : undefined
+
0}
+ fallback={
+ scrollHelpers.handleScroll(event as Event & { currentTarget: HTMLDivElement }) : undefined
+ }
+ >
+
+ {scrollHelpers?.renderSentinel?.()}
+
}
>
-
+
diff --git a/packages/ui/src/components/tool-call/tool-title.ts b/packages/ui/src/components/tool-call/tool-title.ts
index d2abfd0a..6d2526c5 100644
--- a/packages/ui/src/components/tool-call/tool-title.ts
+++ b/packages/ui/src/components/tool-call/tool-title.ts
@@ -74,12 +74,15 @@ function createStaticContext(snapshot: TitleSnapshot): ToolRendererContext {
toolCall: toolCallAccessor,
toolState: toolStateAccessor,
toolName: toolNameAccessor,
+ instanceId: "",
+ sessionId: "",
t,
messageVersion: messageVersionAccessor,
partVersion: partVersionAccessor,
renderMarkdown,
renderAnsi,
renderDiff,
+ renderToolCall: () => null,
scrollHelpers: undefined,
}
}
diff --git a/packages/ui/src/components/tool-call/types.ts b/packages/ui/src/components/tool-call/types.ts
index 6d6d74ec..c3578a07 100644
--- a/packages/ui/src/components/tool-call/types.ts
+++ b/packages/ui/src/components/tool-call/types.ts
@@ -53,12 +53,26 @@ export interface ToolRendererContext {
toolCall: Accessor
toolState: Accessor
toolName: Accessor
+ instanceId: string
+ sessionId: string
t: (key: string, params?: Record) => string
messageVersion?: Accessor
partVersion?: Accessor
renderMarkdown(options: MarkdownRenderOptions): JSXElement | null
renderAnsi(options: AnsiRenderOptions): JSXElement | null
renderDiff(payload: DiffPayload, options?: DiffRenderOptions): JSXElement | null
+ /**
+ * Render another tool call inline. This is provided by the ToolCall shell
+ * to avoid renderer-level imports that would create cyclic dependencies.
+ */
+ renderToolCall?: (options: {
+ toolCall: ToolCallPart
+ messageId?: string
+ messageVersion?: number
+ partVersion?: number
+ sessionId: string
+ forceCollapsed?: boolean
+ }) => JSXElement | null
scrollHelpers?: ToolScrollHelpers
}
diff --git a/packages/ui/src/styles/messaging/tool-call/task.css b/packages/ui/src/styles/messaging/tool-call/task.css
index b1edff5d..83e435ac 100644
--- a/packages/ui/src/styles/messaging/tool-call/task.css
+++ b/packages/ui/src/styles/messaging/tool-call/task.css
@@ -76,6 +76,42 @@
margin: 0;
}
+/* Nested tool calls (child session tool timeline) */
+.tool-call-task-summary .tool-call {
+ /* Tool calls inside the main message stream are borderless.
+ Use an overlay stripe so hover backgrounds don't hide it. */
+ position: relative;
+}
+
+.tool-call-task-summary .tool-call::before {
+ content: "";
+ position: absolute;
+ left: 0;
+ top: 0;
+ bottom: 0;
+ width: 3px;
+ background-color: var(--task-tool-call-stripe, transparent);
+ pointer-events: none;
+ z-index: 2;
+}
+
+.tool-call-task-summary .tool-call.tool-call-status-completed,
+.tool-call-task-summary .tool-call.tool-call-status-success {
+ --task-tool-call-stripe: var(--status-success);
+}
+
+.tool-call-task-summary .tool-call.tool-call-status-running {
+ --task-tool-call-stripe: var(--status-warning);
+}
+
+.tool-call-task-summary .tool-call.tool-call-status-pending {
+ --task-tool-call-stripe: var(--accent-primary);
+}
+
+.tool-call-task-summary .tool-call.tool-call-status-error {
+ --task-tool-call-stripe: var(--status-error);
+}
+
.tool-call-task-item {
display: flex;
align-items: center;