| 1 | package agent |
| 2 | |
| 3 | import ( |
| 4 | "context" |
| 5 | "testing" |
| 6 | |
| 7 | "reasonix/internal/event" |
| 8 | "reasonix/internal/provider" |
| 9 | "reasonix/internal/tool" |
| 10 | ) |
| 11 | |
| 12 | func TestNaturalCompletionAcceptsVisibleAnswerInOneRound(t *testing.T) { |
| 13 | prov := &scriptedProvider{name: "natural-completion", turns: [][]provider.Chunk{{ |
| 14 | {Type: provider.ChunkText, Text: "The requested work is complete."}, |
| 15 | {Type: provider.ChunkDone}, |
| 16 | }}} |
| 17 | a := New(prov, tool.NewRegistry(), NewSession(""), Options{}, event.Discard) |
| 18 | |
| 19 | if err := a.Run(context.Background(), "do the work"); err != nil { |
| 20 | t.Fatalf("Run: %v", err) |
| 21 | } |
| 22 | if prov.call != 1 { |
| 23 | t.Fatalf("provider calls = %d, want one natural completion round", prov.call) |
| 24 | } |
| 25 | if len(prov.requests) != 1 || len(prov.requests[0].Tools) != 0 { |
| 26 | t.Fatalf("provider tools = %#v, want no finish schema", prov.requests) |
| 27 | } |
| 28 | } |
| 29 | |
| 30 | func TestNaturalCompletionReplaysLegacyFinishHistoryWithoutSchema(t *testing.T) { |
| 31 | sess := NewSession("") |
| 32 | sess.Add(provider.Message{Role: provider.RoleUser, Content: "legacy request"}) |
| 33 | sess.Add(provider.Message{ |
| 34 | Role: provider.RoleAssistant, |
| 35 | Content: "Legacy answer.", |
| 36 | ToolCalls: []provider.ToolCall{{ |
| 37 | ID: "legacy-finish", Name: "finish", Arguments: `{"outcome":"completed"}`, |
| 38 | }}, |
| 39 | }) |
| 40 | sess.Add(provider.Message{ |
| 41 | Role: provider.RoleTool, ToolCallID: "legacy-finish", Name: "finish", |
| 42 | Content: "Turn finalization accepted by the host.", |
| 43 | }) |
| 44 | prov := &scriptedProvider{name: "natural-completion-legacy", turns: [][]provider.Chunk{{ |
| 45 | {Type: provider.ChunkText, Text: "The next turn also ends naturally."}, |
| 46 | {Type: provider.ChunkDone}, |
| 47 | }}} |
| 48 | a := New(prov, tool.NewRegistry(), sess, Options{}, event.Discard) |
| 49 | |
| 50 | if err := a.Run(context.Background(), "continue"); err != nil { |
| 51 | t.Fatalf("Run: %v", err) |
| 52 | } |
| 53 | if len(prov.requests) != 1 || len(prov.requests[0].Tools) != 0 { |
| 54 | t.Fatalf("provider tools = %#v, want legacy replay without finish schema", prov.requests) |
| 55 | } |
| 56 | var sawCall, sawResult bool |
| 57 | for _, message := range prov.requests[0].Messages { |
| 58 | for _, call := range message.ToolCalls { |
| 59 | if call.ID == "legacy-finish" && call.Name == "finish" { |
| 60 | sawCall = true |
| 61 | } |
| 62 | } |
| 63 | if message.Role == provider.RoleTool && message.ToolCallID == "legacy-finish" && message.Name == "finish" { |
| 64 | sawResult = true |
| 65 | } |
| 66 | } |
| 67 | if !sawCall || !sawResult { |
| 68 | t.Fatalf("legacy finish pair was not preserved in provider history: call=%t result=%t", sawCall, sawResult) |
| 69 | } |
| 70 | } |
| 71 |