| 1 | package anthropic |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "encoding/json" |
| 6 | "strings" |
| 7 | "testing" |
| 8 | |
| 9 | "reasonix/internal/provider" |
| 10 | ) |
| 11 | |
| 12 | func TestBuildRequestExcludesToolExecution(t *testing.T) { |
| 13 | code := 1 |
| 14 | msgs := provider.ModelMessages([]provider.Message{ |
| 15 | {Role: provider.RoleUser, Content: "run tests"}, |
| 16 | {Role: provider.RoleAssistant, ToolCalls: []provider.ToolCall{ |
| 17 | {ID: "call_1", Name: "bash", Arguments: `{"command":"go test ./..."}`}, |
| 18 | }}, |
| 19 | { |
| 20 | Role: provider.RoleTool, ToolCallID: "call_1", Name: "bash", Content: "FAIL", |
| 21 | ToolExecution: &provider.ToolExecution{ |
| 22 | Kind: "shell", Shell: "bash", State: "failed", ExitCode: &code, |
| 23 | FailurePhase: "execution", OutputTail: "中文stderr-marker-must-not-leak", |
| 24 | }, |
| 25 | }, |
| 26 | }) |
| 27 | req := (&client{model: "claude-test"}).buildRequest(context.Background(), provider.Request{Messages: msgs}) |
| 28 | body, err := json.Marshal(req) |
| 29 | if err != nil { |
| 30 | t.Fatal(err) |
| 31 | } |
| 32 | s := string(body) |
| 33 | for _, banned := range []string{"tool_execution", "outputTail", "中文stderr-marker-must-not-leak", "failurePhase", "mutationRisk"} { |
| 34 | if strings.Contains(s, banned) { |
| 35 | t.Fatalf("anthropic wire leaked %q: %s", banned, s) |
| 36 | } |
| 37 | } |
| 38 | if !strings.Contains(s, "tool_result") || !strings.Contains(s, "call_1") { |
| 39 | t.Fatalf("anthropic tool_result missing: %s", s) |
| 40 | } |
| 41 | } |
| 42 | |
| 43 | func TestBuildRequestStableWhenLocalExecutionAdded(t *testing.T) { |
| 44 | base := []provider.Message{ |
| 45 | {Role: provider.RoleUser, Content: "run"}, |
| 46 | {Role: provider.RoleAssistant, ToolCalls: []provider.ToolCall{{ID: "c1", Name: "bash", Arguments: `{"command":"true"}`}}}, |
| 47 | {Role: provider.RoleTool, ToolCallID: "c1", Name: "bash", Content: "ok"}, |
| 48 | } |
| 49 | code := 0 |
| 50 | withMeta := append([]provider.Message(nil), base...) |
| 51 | withMeta[2].ToolExecution = &provider.ToolExecution{Kind: "shell", OutputTail: "noise", ExitCode: &code} |
| 52 | a, err := json.Marshal((&client{model: "claude-test"}).buildRequest(context.Background(), provider.Request{Messages: provider.ModelMessages(base)})) |
| 53 | if err != nil { |
| 54 | t.Fatal(err) |
| 55 | } |
| 56 | b, err := json.Marshal((&client{model: "claude-test"}).buildRequest(context.Background(), provider.Request{Messages: provider.ModelMessages(withMeta)})) |
| 57 | if err != nil { |
| 58 | t.Fatal(err) |
| 59 | } |
| 60 | if string(a) != string(b) { |
| 61 | t.Fatalf("anthropic request diverged\nbase=%s\nmeta=%s", a, b) |
| 62 | } |
| 63 | } |
| 64 |