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:
parent
fb025db6c1
commit
78a319d5fe
2 changed files with 14 additions and 6 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -47,3 +47,6 @@ dist/
|
||||||
|
|
||||||
# Windows Application Icon/Resource
|
# Windows Application Icon/Resource
|
||||||
*.syso
|
*.syso
|
||||||
|
|
||||||
|
# ZCF workflow (local development)
|
||||||
|
.zcf/
|
||||||
|
|
|
||||||
|
|
@ -370,13 +370,15 @@ func parseStreamingResponse(stream *ssestream.Stream[anthropic.MessageStreamEven
|
||||||
case "content_block_start":
|
case "content_block_start":
|
||||||
block := evt.AsContentBlockStart()
|
block := evt.AsContentBlockStart()
|
||||||
if block.ContentBlock.Type == "tool_use" {
|
if block.ContentBlock.Type == "tool_use" {
|
||||||
// 初始化工具调用
|
// 初始化工具调用,捕获 ID 和 Name
|
||||||
currentToolCall = &struct {
|
currentToolCall = &struct {
|
||||||
ID string
|
ID string
|
||||||
Name string
|
Name string
|
||||||
Args strings.Builder
|
Args strings.Builder
|
||||||
Index int64
|
Index int64
|
||||||
}{
|
}{
|
||||||
|
ID: block.ContentBlock.ID,
|
||||||
|
Name: block.ContentBlock.Name,
|
||||||
Index: block.Index,
|
Index: block.Index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -397,11 +399,14 @@ func parseStreamingResponse(stream *ssestream.Stream[anthropic.MessageStreamEven
|
||||||
|
|
||||||
case "content_block_stop":
|
case "content_block_stop":
|
||||||
// 完成当前工具调用,添加到列表
|
// 完成当前工具调用,添加到列表
|
||||||
if currentToolCall != nil && currentToolCall.Name != "" {
|
if currentToolCall != nil {
|
||||||
var args map[string]any
|
var args map[string]any
|
||||||
argsStr := currentToolCall.Args.String()
|
argsStr := currentToolCall.Args.String()
|
||||||
if err := json.Unmarshal([]byte(argsStr), &args); err != nil {
|
if argsStr == "" {
|
||||||
log.Printf("anthropic: failed to decode tool call input for %q: %v", currentToolCall.Name, err)
|
// 如果没有参数,使用空对象
|
||||||
|
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}
|
args = map[string]any{"raw": argsStr}
|
||||||
}
|
}
|
||||||
toolCalls = append(toolCalls, ToolCall{
|
toolCalls = append(toolCalls, ToolCall{
|
||||||
|
|
@ -419,10 +424,10 @@ func parseStreamingResponse(stream *ssestream.Stream[anthropic.MessageStreamEven
|
||||||
usage.OutputTokens = msgDelta.Usage.OutputTokens
|
usage.OutputTokens = msgDelta.Usage.OutputTokens
|
||||||
|
|
||||||
case "message_stop":
|
case "message_stop":
|
||||||
// 消息完成,无需处理
|
// 消息完成
|
||||||
|
|
||||||
case "error":
|
case "error":
|
||||||
return nil, fmt.Errorf("stream error: %v", evt)
|
return nil, fmt.Errorf("stream error: type=%s, error=%v", evt.Type, evt)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue