fix(server): extract tool result content from SDK blocks

The Claude SDK returns tool_result blocks with `content` as a string
containing the actual command output. Previously, handleToolResult only
set output when there were file changes (entry?.files), missing all
other tool outputs like shell command results.

Now buildToolOutput extracts block.content and wraps it as
{ result: { output: content } } which the frontend parsers expect.
This fixes "No additional details available" when expanding tool calls.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Mohamed Boudra
2025-11-28 18:52:13 +00:00
co-authored by Claude
parent e80989ea78
commit eea28d59c9
@@ -1012,6 +1012,10 @@ class ClaudeAgentSession implements AgentSession {
const server = entry?.server ?? block.server ?? "tool";
const tool = entry?.name ?? block.tool_name ?? "tool";
const status = block.is_error ? "failed" : "completed";
// Extract output from block.content (SDK always returns content as string)
const output = this.buildToolOutput(block, entry);
this.pushToolCall(
{
server,
@@ -1021,7 +1025,7 @@ class ClaudeAgentSession implements AgentSession {
displayName: this.buildToolDisplayName(entry),
kind: this.getToolKind(entry?.classification),
input: entry?.input,
output: !block.is_error && entry?.files?.length ? { files: entry.files } : undefined,
output,
error: block.is_error ? block : undefined,
},
items
@@ -1031,6 +1035,29 @@ class ClaudeAgentSession implements AgentSession {
}
}
private buildToolOutput(
block: ClaudeContentChunk,
entry: ToolUseCacheEntry | undefined
): Record<string, unknown> | undefined {
if (block.is_error) {
return undefined;
}
const result: Record<string, unknown> = {};
// SDK tool_result blocks have content as a string
if (typeof block.content === "string" && block.content.length > 0) {
result.result = { output: block.content };
}
// Preserve file changes tracked during tool execution
if (entry?.files?.length) {
result.files = entry.files;
}
return Object.keys(result).length > 0 ? result : undefined;
}
private mapPartialEvent(event: SDKPartialAssistantMessage["event"]): AgentTimelineItem[] {
if (event.type === "content_block_start" && (event.content_block as ClaudeContentChunk | undefined)?.type === "tool_use") {
const block = event.content_block as ClaudeContentChunk;