fix: sanitize tool call IDs before sending to Anthropic API
Session history from other providers (e.g. OpenAI/Codex) can contain tool call IDs with dots and colons (e.g. `functions.web_fetch:0`) that violate Anthropic's `^[a-zA-Z0-9_-]+$` constraint, causing 400 errors on every subsequent message. Add sanitizeToolID() to replace invalid characters with hyphens, applied consistently to both tool_use and tool_result blocks so IDs still match each other after transformation. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
214b201bfa
commit
d24620f32d
1 changed files with 20 additions and 3 deletions
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
"github.com/anthropics/anthropic-sdk-go"
|
"github.com/anthropics/anthropic-sdk-go"
|
||||||
"github.com/anthropics/anthropic-sdk-go/option"
|
"github.com/anthropics/anthropic-sdk-go/option"
|
||||||
|
|
@ -56,6 +57,22 @@ func (p *ClaudeProvider) GetDefaultModel() string {
|
||||||
return "claude-sonnet-4-5-20250929"
|
return "claude-sonnet-4-5-20250929"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// sanitizeToolID replaces characters not allowed in Anthropic tool use IDs
|
||||||
|
// (which must match ^[a-zA-Z0-9-]+$) with hyphens. The same transformation is
|
||||||
|
// applied to both tool_use and tool_result blocks so their IDs still match.
|
||||||
|
func sanitizeToolID(id string) string {
|
||||||
|
var b strings.Builder
|
||||||
|
b.Grow(len(id))
|
||||||
|
for _, r := range id {
|
||||||
|
if (r >= 'a' && r <= 'z') || (r >= 'A' && r <= 'Z') || (r >= '0' && r <= '9') || r == '-' {
|
||||||
|
b.WriteRune(r)
|
||||||
|
} else {
|
||||||
|
b.WriteRune('-')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return b.String()
|
||||||
|
}
|
||||||
|
|
||||||
func buildClaudeParams(messages []Message, tools []ToolDefinition, model string, options map[string]interface{}) (anthropic.MessageNewParams, error) {
|
func buildClaudeParams(messages []Message, tools []ToolDefinition, model string, options map[string]interface{}) (anthropic.MessageNewParams, error) {
|
||||||
var system []anthropic.TextBlockParam
|
var system []anthropic.TextBlockParam
|
||||||
var anthropicMessages []anthropic.MessageParam
|
var anthropicMessages []anthropic.MessageParam
|
||||||
|
|
@ -67,7 +84,7 @@ func buildClaudeParams(messages []Message, tools []ToolDefinition, model string,
|
||||||
case "user":
|
case "user":
|
||||||
if msg.ToolCallID != "" {
|
if msg.ToolCallID != "" {
|
||||||
anthropicMessages = append(anthropicMessages,
|
anthropicMessages = append(anthropicMessages,
|
||||||
anthropic.NewUserMessage(anthropic.NewToolResultBlock(msg.ToolCallID, msg.Content, false)),
|
anthropic.NewUserMessage(anthropic.NewToolResultBlock(sanitizeToolID(msg.ToolCallID), msg.Content, false)),
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
anthropicMessages = append(anthropicMessages,
|
anthropicMessages = append(anthropicMessages,
|
||||||
|
|
@ -81,7 +98,7 @@ func buildClaudeParams(messages []Message, tools []ToolDefinition, model string,
|
||||||
blocks = append(blocks, anthropic.NewTextBlock(msg.Content))
|
blocks = append(blocks, anthropic.NewTextBlock(msg.Content))
|
||||||
}
|
}
|
||||||
for _, tc := range msg.ToolCalls {
|
for _, tc := range msg.ToolCalls {
|
||||||
blocks = append(blocks, anthropic.NewToolUseBlock(tc.ID, tc.Arguments, tc.Name))
|
blocks = append(blocks, anthropic.NewToolUseBlock(sanitizeToolID(tc.ID), tc.Arguments, tc.Name))
|
||||||
}
|
}
|
||||||
anthropicMessages = append(anthropicMessages, anthropic.NewAssistantMessage(blocks...))
|
anthropicMessages = append(anthropicMessages, anthropic.NewAssistantMessage(blocks...))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -91,7 +108,7 @@ func buildClaudeParams(messages []Message, tools []ToolDefinition, model string,
|
||||||
}
|
}
|
||||||
case "tool":
|
case "tool":
|
||||||
anthropicMessages = append(anthropicMessages,
|
anthropicMessages = append(anthropicMessages,
|
||||||
anthropic.NewUserMessage(anthropic.NewToolResultBlock(msg.ToolCallID, msg.Content, false)),
|
anthropic.NewUserMessage(anthropic.NewToolResultBlock(sanitizeToolID(msg.ToolCallID), msg.Content, false)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue