返回 DeepSeek-Reasonix
readiness_gate_test.go
根目录 / internal / acp / readiness_gate_test.go
1 package acp
2
3 import (
4 "context"
5 "encoding/json"
6 "fmt"
7 "strings"
8 "testing"
9
10 "reasonix/internal/agent"
11 "reasonix/internal/event"
12 )
13
14 func TestServePromptReadinessGateFailureEndsTurnWithWarning(t *testing.T) {
15 const secret = "ghp_abcdefghijklmnopqrstuvwxyz"
16 const opaqueSecret = "readinessSecretAbc123"
17 longReason := "missing verification; Authorization: Bearer " + secret +
18 " credential " + opaqueSecret + "; details=" + strings.Repeat("x", 3_000)
19 factory := &fakeFactory{behavior: func(context.Context, event.Sink, string) error {
20 return fmt.Errorf("turn stopped: %w", &agent.FinalReadinessError{Attempts: 1, Reason: longReason, Missing: []string{"verify"}})
21 }}
22 client, stop := startServer(t, factory)
23 defer stop()
24
25 client.call(t, "initialize", InitializeParams{ProtocolVersion: 1})
26 newResp := client.call(t, "session/new", SessionNewParams{})
27 var nr SessionNewResult
28 if err := json.Unmarshal(newResp.Result, &nr); err != nil {
29 t.Fatalf("session/new result: %v", err)
30 }
31
32 promptCh := client.callAsync("session/prompt", SessionPromptParams{
33 SessionID: nr.SessionID,
34 Prompt: []ContentBlock{{Type: "text", Text: "do the thing"}},
35 })
36 notifs, resp := drainPrompt(t, client, promptCh)
37 var pr SessionPromptResult
38 if err := json.Unmarshal(resp.Result, &pr); err != nil {
39 t.Fatalf("prompt result: %v", err)
40 }
41 if pr.StopReason != StopEndTurn {
42 t.Fatalf("stopReason = %q, want end_turn", pr.StopReason)
43 }
44
45 warned := false
46 for _, n := range notifs {
47 var params SessionUpdateParams
48 if err := json.Unmarshal(n.Params, &params); err != nil {
49 continue
50 }
51 upd, ok := params.Update.(map[string]any)
52 if !ok || upd["sessionUpdate"] != "agent_message_chunk" {
53 continue
54 }
55 content, _ := upd["content"].(map[string]any)
56 text, _ := content["text"].(string)
57 if strings.Contains(text, "[warning]") && strings.Contains(text, "missing verification") {
58 if strings.Contains(text, secret) || strings.Contains(text, opaqueSecret) {
59 t.Fatalf("readiness warning leaked credential: %q", text)
60 }
61 if len(text) > len("\n\n[warning] ")+2_048 {
62 t.Fatalf("readiness warning length = %d, want at most %d", len(text), len("\n\n[warning] ")+2_048)
63 }
64 warned = true
65 }
66 }
67 if !warned {
68 t.Fatalf("no readiness warning chunk in notifications: %+v", notifs)
69 }
70 }
71
71 lines GO