fix: render tool calls above text response for external providers
- Add insertChildBefore() to Box component for positional insertion - In chat controller, insert tool_execution components before the last assistant message component (instead of appending after) when tools were executed externally - Simplify agent-loop externalToolExecution path back to basic tool_execution_start/end emission - Toolcall streaming events are filtered in the Claude Code adapter to prevent duplicate rendering via message_update Result: externally-executed tool calls render above the text response, matching the expected visual flow. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
bbea8460b5
commit
263d725ecd
3 changed files with 25 additions and 3 deletions
|
|
@ -234,8 +234,9 @@ async function runLoop(
|
|||
|
||||
const toolResults: ToolResultMessage[] = [];
|
||||
if (hasMoreToolCalls && config.externalToolExecution) {
|
||||
// External execution mode: tools were handled by the provider (e.g., Claude Code SDK).
|
||||
// Emit synthetic tool events for TUI rendering but skip local dispatch.
|
||||
// External execution mode: tools were handled by the provider
|
||||
// (e.g., Claude Code SDK). Emit tool_execution events for each
|
||||
// tool call. The TUI adds these as components after the message.
|
||||
for (const tc of toolCalls as AgentToolCall[]) {
|
||||
stream.push({
|
||||
type: "tool_execution_start",
|
||||
|
|
|
|||
|
|
@ -210,7 +210,18 @@ export async function handleAgentEvent(host: InteractiveModeStateHost & {
|
|||
host.ui,
|
||||
);
|
||||
component.setExpanded(host.toolOutputExpanded);
|
||||
host.chatContainer.addChild(component);
|
||||
|
||||
// For external tool execution: insert tool components before the
|
||||
// last message component so tools render above the text response.
|
||||
// The last child is the message that just finished streaming.
|
||||
const children = host.chatContainer.children;
|
||||
const lastChild = children.length > 0 ? children[children.length - 1] : undefined;
|
||||
if (lastChild instanceof AssistantMessageComponent && !host.streamingComponent) {
|
||||
host.chatContainer.insertChildBefore(component, lastChild);
|
||||
} else {
|
||||
host.chatContainer.addChild(component);
|
||||
}
|
||||
|
||||
host.pendingTools.set(event.toolCallId, component);
|
||||
host.ui.requestRender();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,6 +31,16 @@ export class Box implements Component {
|
|||
this.invalidateCache();
|
||||
}
|
||||
|
||||
insertChildBefore(component: Component, before: Component): void {
|
||||
const index = this.children.indexOf(before);
|
||||
if (index !== -1) {
|
||||
this.children.splice(index, 0, component);
|
||||
} else {
|
||||
this.children.push(component);
|
||||
}
|
||||
this.invalidateCache();
|
||||
}
|
||||
|
||||
removeChild(component: Component): void {
|
||||
const index = this.children.indexOf(component);
|
||||
if (index !== -1) {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue