返回 DeepSeek-Reasonix
unfinished_todo_readiness_test.go
根目录 / internal / agent / unfinished_todo_readiness_test.go
1 package agent
2
3 import (
4 "context"
5 "testing"
6
7 "reasonix/internal/evidence"
8 "reasonix/internal/provider"
9 "reasonix/internal/tool"
10 )
11
12 // TestOpenTurnMayEndWithIncompleteTodosAfterWrite proves an ordinary session
13 // can leave a partial cross-turn plan without entering delivery recovery.
14 func TestOpenTurnMayEndWithIncompleteTodosAfterWrite(t *testing.T) {
15 todoWrite, ok := tool.LookupBuiltin("todo_write")
16 if !ok {
17 t.Fatal("todo_write builtin not registered")
18 }
19 reg := tool.NewRegistry()
20 reg.Add(fakeTool{name: "write_file", readOnly: false})
21 reg.Add(todoWrite)
22 prov := &scriptedProvider{name: "p", turns: [][]provider.Chunk{
23 {
24 toolCallChunk("c1", "write_file", `{"path":"changed.go","content":"package main"}`),
25 toolCallChunk("c2", "todo_write", `{"todos":[{"content":"Edit code","status":"in_progress"}]}`),
26 {Type: provider.ChunkDone},
27 },
28 {{Type: provider.ChunkText, Text: "done, more steps remain for later turns"}, {Type: provider.ChunkDone}},
29 }}
30 sink := &readinessAuditSink{}
31 a := New(prov, reg, NewSession(""), Options{}, sink)
32
33 if err := a.Run(withNoClosedLoop(context.Background()), "edit with todo and leave remaining steps for later"); err != nil {
34 t.Fatalf("open turn with incomplete todos must not fail the run: %v", err)
35 }
36 if prov.call != 2 {
37 t.Fatalf("provider calls = %d, want 2 (write + final, no readiness retry)", prov.call)
38 }
39 for _, audit := range sink.events {
40 if audit.Result == evidence.ReadinessErrored {
41 t.Fatalf("open turn recorded errored readiness audit: %+v", audit)
42 }
43 }
44 }
45
45 lines GO