fix: handle previously swallowed json.Unmarshal errors (#78)

- Propagate json.Unmarshal error in buildAnthropicParams when parsing
  tool call arguments, preventing silent empty-map fallback on malformed JSON
- Return explicit error message in ParseComments when comments JSON
  string fails to unmarshal, instead of silently ignoring

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Shi Peipei 2026-06-08 21:03:00 +08:00 committed by GitHub
parent adb9ac8b4e
commit 4043e9ee33
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 24 additions and 8 deletions

View file

@ -523,7 +523,10 @@ func (c *AnthropicClient) CompletionsWithCtx(ctx context.Context, req ChatReques
model = c.cfg.Model
}
params := c.buildAnthropicParams(model, req)
params, err := c.buildAnthropicParams(model, req)
if err != nil {
return nil, err
}
var opts []option.RequestOption
for k, v := range c.cfg.ExtraBody {
@ -539,7 +542,7 @@ func (c *AnthropicClient) CompletionsWithCtx(ctx context.Context, req ChatReques
}
// buildAnthropicParams converts the shared ChatRequest into Anthropic SDK parameters.
func (c *AnthropicClient) buildAnthropicParams(model string, req ChatRequest) anthropic.MessageNewParams {
func (c *AnthropicClient) buildAnthropicParams(model string, req ChatRequest) (anthropic.MessageNewParams, error) {
var systemBlocks []anthropic.TextBlockParam
var messages []anthropic.MessageParam
var pendingToolResults []Message
@ -578,7 +581,9 @@ func (c *AnthropicClient) buildAnthropicParams(model string, req ChatRequest) an
for _, tc := range msg.ToolCalls {
argsMap := map[string]any{}
if tc.Function.Arguments != "" {
json.Unmarshal([]byte(tc.Function.Arguments), &argsMap)
if err := json.Unmarshal([]byte(tc.Function.Arguments), &argsMap); err != nil {
return anthropic.MessageNewParams{}, fmt.Errorf("invalid tool call arguments for %s: %w", tc.Function.Name, err)
}
}
blocks = append(blocks, anthropic.NewToolUseBlock(tc.ID, argsMap, tc.Function.Name))
}
@ -644,7 +649,7 @@ func (c *AnthropicClient) buildAnthropicParams(model string, req ChatRequest) an
params.Temperature = anthropic.Float(*req.Temperature)
}
return params
return params, nil
}
func buildToolInputSchema(params map[string]any) anthropic.ToolInputSchemaParam {

View file

@ -110,7 +110,10 @@ func TestBuildAnthropicParams_CacheControl(t *testing.T) {
},
}
params := client.buildAnthropicParams("claude-sonnet-4-20250514", req)
params, err := client.buildAnthropicParams("claude-sonnet-4-20250514", req)
if err != nil {
t.Fatalf("buildAnthropicParams: %v", err)
}
t.Run("last system block has cache control", func(t *testing.T) {
if len(params.System) < 2 {
@ -169,7 +172,10 @@ func TestBuildAnthropicParams_CacheControl_NoTools(t *testing.T) {
},
}
params := client.buildAnthropicParams("claude-sonnet-4-20250514", req)
params, err := client.buildAnthropicParams("claude-sonnet-4-20250514", req)
if err != nil {
t.Fatalf("buildAnthropicParams: %v", err)
}
if len(params.System) == 0 {
t.Fatal("expected system blocks")
@ -195,7 +201,10 @@ func TestBuildAnthropicParams_CacheControl_NoSystem(t *testing.T) {
},
}
params := client.buildAnthropicParams("claude-sonnet-4-20250514", req)
params, err := client.buildAnthropicParams("claude-sonnet-4-20250514", req)
if err != nil {
t.Fatalf("buildAnthropicParams: %v", err)
}
if len(params.System) != 0 {
t.Errorf("expected no system blocks, got %d", len(params.System))

View file

@ -38,7 +38,9 @@ func ParseComments(args map[string]any) ([]model.LlmComment, string) {
if arr, ok := args["comments"].([]any); ok && len(arr) > 0 {
rawComments = arr
} else if s, ok := args["comments"].(string); ok && s != "" {
_ = json.Unmarshal([]byte(s), &rawComments)
if err := json.Unmarshal([]byte(s), &rawComments); err != nil {
return nil, fmt.Sprintf("Error: failed to parse 'comments' JSON string: %v", err)
}
}
if len(rawComments) == 0 {
raw, _ := json.Marshal(args)