diff --git a/agentscope-core/src/main/java/io/agentscope/core/agent/StructuredOutputHook.java b/agentscope-core/src/main/java/io/agentscope/core/agent/StructuredOutputHook.java index cf4f9edd6..d9cc790d2 100644 --- a/agentscope-core/src/main/java/io/agentscope/core/agent/StructuredOutputHook.java +++ b/agentscope-core/src/main/java/io/agentscope/core/agent/StructuredOutputHook.java @@ -145,6 +145,29 @@ private void handlePostReasoning(PostReasoningEvent event) { boolean hasCall = !msg.getContentBlocks(ToolUseBlock.class).isEmpty(); + // Capture metadata from reasoning message (including _chat_usage) + // This ensures metadata is preserved even when generate_response is called + if (hasCall) { + ChatUsage usage = msg.getChatUsage(); + if (usage != null) { + // Aggregate usage from all reasoning rounds + if (this.aggregatedUsage == null) { + this.aggregatedUsage = usage; + } else { + this.aggregatedUsage = ChatUsage.builder() + .inputTokens(this.aggregatedUsage.getInputTokens() + usage.getInputTokens()) + .outputTokens(this.aggregatedUsage.getOutputTokens() + usage.getOutputTokens()) + .time(this.aggregatedUsage.getTime() + usage.getTime()) + .build(); + } + } + // Capture ThinkingBlock (keep the last one) + ThinkingBlock thinking = msg.getFirstContentBlock(ThinkingBlock.class); + if (thinking != null) { + this.aggregatedThinking = thinking; + } + } + if (!hasCall && retryCount < MAX_RETRIES) { retryCount++; log.debug(