MCPcopy Index your code
hub / github.com/codehamr/codehamr / TestChatFallsBackWhenReasoningEffortRejected

Function TestChatFallsBackWhenReasoningEffortRejected

internal/llm/llm_test.go:638–690  ·  view source on GitHub ↗

TestChatFallsBackWhenReasoningEffortRejected: newer OpenAI models reject tools + reasoning_effort on /v1/chat/completions with a 400. postChat must drop the field, retry once, and stay sticky for the Client's life, else every turn burns a 400.

(t *testing.T)

Source from the content-addressed store, hash-verified

636 t.Fatalf("reasoning must not leak into final message content: %+v", done.Final)
637 }
638 if done.Tokens != 3 {
639 t.Fatalf("want 3 tokens, got %d", done.Tokens)
640 }
641}
642
643// TestChatFallsBackWhenReasoningEffortRejected: newer OpenAI models reject tools +
644// reasoning_effort on /v1/chat/completions with a 400. postChat must drop the
645// field, retry once, and stay sticky for the Client's life, else every turn
646// burns a 400.
647func TestChatFallsBackWhenReasoningEffortRejected(t *testing.T) {
648 var bodies []string
649 srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
650 b, _ := io.ReadAll(r.Body)
651 bodies = append(bodies, string(b))
652 if strings.Contains(string(b), `"reasoning_effort"`) {
653 w.WriteHeader(400)
654 fmt.Fprintln(w, `{`)
655 fmt.Fprintln(w, ` "error": {`)
656 fmt.Fprintln(w, ` "message": "Function tools with reasoning_effort are not supported for this model in /v1/chat/completions. Please use /v1/responses instead.",`)
657 fmt.Fprintln(w, ` "param": "reasoning_effort"`)
658 fmt.Fprintln(w, ` }`)
659 fmt.Fprintln(w, `}`)
660 return
661 }
662 sseOK(w, []string{
663 `{"choices":[{"delta":{"content":"ok"}}],"usage":{"completion_tokens":1}}`,
664 })
665 }))
666 defer srv.Close()
667
668 c := New(srv.URL, "cloud-model", "")
669
670 // First turn: 400 → fallback → success.
671 for _, e := range collect(c.Chat(context.Background(), nil, nil)) {
672 if e.Kind == EventError {
673 t.Fatalf("first turn must succeed via fallback, got error: %v", e.Err)
674 }
675 }
676 if len(bodies) != 2 {
677 t.Fatalf("first turn should send initial + retry (2 requests), got %d", len(bodies))
678 }
679 if !strings.Contains(bodies[0], `"reasoning_effort"`) {
680 t.Fatalf("first attempt should send reasoning_effort: %s", bodies[0])
681 }
682 if strings.Contains(bodies[1], `"reasoning_effort"`) {
683 t.Fatalf("retry must drop reasoning_effort: %s", bodies[1])
684 }
685
686 // Second turn on the same Client: flag is sticky, no 400, no retry.
687 bodies = nil
688 for _, e := range collect(c.Chat(context.Background(), nil, nil)) {
689 if e.Kind == EventError {
690 t.Fatalf("second turn must not error: %v", e.Err)
691 }
692 }
693 if len(bodies) != 1 {

Callers

nothing calls this directly

Calls 4

sseOKFunction · 0.85
collectFunction · 0.85
ChatMethod · 0.80
NewFunction · 0.70

Tested by

no test coverage detected