refactor: complete tool call support in streaming response

完善工具调用支持的关键修复:
- 在 content_block_start 时捕获工具调用的 ID 和 Name
- 修复之前只初始化 Index 而忽略 ID/Name 的问题
- 改进空参数处理(使用空对象而非 panic)
- 增强错误日志,包含实际参数内容以便调试

技术细节:
- block.ContentBlock.ID -> currentToolCall.ID
- block.ContentBlock.Name -> currentToolCall.Name
- 处理空 JSON 字符串的情况
- 错误日志格式:包含 args 字符串便于诊断

这确保了需要工具调用的场景能够正常工作。
This commit is contained in:
ZaneTung 2026-03-05 17:19:31 +08:00
parent 8358d35374
commit 3332220940
2 changed files with 14 additions and 6 deletions

3
.gitignore vendored
View file

@ -47,3 +47,6 @@ dist/
# Windows Application Icon/Resource
*.syso
# ZCF workflow (local development)
.zcf/

View file

@ -370,13 +370,15 @@ func parseStreamingResponse(stream *ssestream.Stream[anthropic.MessageStreamEven
case "content_block_start":
block := evt.AsContentBlockStart()
if block.ContentBlock.Type == "tool_use" {
// 初始化工具调用
// 初始化工具调用,捕获 ID 和 Name
currentToolCall = &struct {
ID string
Name string
Args strings.Builder
Index int64
}{
ID: block.ContentBlock.ID,
Name: block.ContentBlock.Name,
Index: block.Index,
}
}
@ -397,11 +399,14 @@ func parseStreamingResponse(stream *ssestream.Stream[anthropic.MessageStreamEven
case "content_block_stop":
// 完成当前工具调用,添加到列表
if currentToolCall != nil && currentToolCall.Name != "" {
if currentToolCall != nil {
var args map[string]any
argsStr := currentToolCall.Args.String()
if err := json.Unmarshal([]byte(argsStr), &args); err != nil {
log.Printf("anthropic: failed to decode tool call input for %q: %v", currentToolCall.Name, err)
if argsStr == "" {
// 如果没有参数,使用空对象
args = make(map[string]any)
} else if err := json.Unmarshal([]byte(argsStr), &args); err != nil {
log.Printf("anthropic: failed to decode tool call input for %q: %v (args: %s)", currentToolCall.Name, err, argsStr)
args = map[string]any{"raw": argsStr}
}
toolCalls = append(toolCalls, ToolCall{
@ -419,10 +424,10 @@ func parseStreamingResponse(stream *ssestream.Stream[anthropic.MessageStreamEven
usage.OutputTokens = msgDelta.Usage.OutputTokens
case "message_stop":
// 消息完成,无需处理
// 消息完成
case "error":
return nil, fmt.Errorf("stream error: %v", evt)
return nil, fmt.Errorf("stream error: type=%s, error=%v", evt.Type, evt)
}
}