返回 DeepSeek-Reasonix
nested_tool_leak_test.go
根目录 / internal / agent / nested_tool_leak_test.go
1 package agent
2
3 import (
4 "context"
5 "testing"
6
7 "reasonix/internal/event"
8 "reasonix/internal/jobs"
9 "reasonix/internal/provider"
10 )
11
12 func TestBackgroundTaskToolEventsStayNestedUnderParentCall(t *testing.T) {
13 finalText := []provider.Chunk{{Type: provider.ChunkText, Text: "done"}, {Type: provider.ChunkDone}}
14 sub := &scriptedProvider{name: "sub", turns: [][]provider.Chunk{
15 {toolCallChunk("c1", "bash", `{"command":"ls"}`), {Type: provider.ChunkDone}},
16 finalText, finalText,
17 }}
18 task := NewTaskTool(sub, nil, evidenceRegistry(), 20, 0, 0, 0, 0, 0, 0, 0.0, "", "sys", nil, 0, "", "", nil).
19 WithTranscripts(NewSubagentStore(t.TempDir()), t.TempDir(), "base-model", "base-effort")
20 jm := jobs.NewManager(event.Discard)
21 defer jm.Close()
22 rec := &recordSink{}
23 ctx := withCallContext(testTaskContext(), "task-call", rec, nil, false)
24 ctx = jobs.WithSession(ctx, "parent-session")
25 ctx = jobs.WithManager(ctx, jm)
26
27 out, err := task.Execute(ctx, []byte(`{"prompt":"list","run_in_background":true}`))
28 if err != nil {
29 t.Fatal(err)
30 }
31 res := jm.WaitForSession(context.Background(), "parent-session", []string{extractJobID(out)}, 5)
32 if len(res) != 1 || res[0].Status != jobs.Done {
33 t.Fatalf("job = %+v", res)
34 }
35 rec.mu.Lock()
36 defer rec.mu.Unlock()
37 seen := 0
38 for _, e := range rec.evs {
39 if e.Tool.ID == "" || e.Tool.ID == "task-call" {
40 continue
41 }
42 seen++
43 if e.Tool.ParentID != "task-call" {
44 t.Errorf("event kind %v tool %q id %q has ParentID %q, want task-call", e.Kind, e.Tool.Name, e.Tool.ID, e.Tool.ParentID)
45 }
46 }
47 if seen == 0 {
48 t.Fatal("no sub-agent tool events observed")
49 }
50 }
51
51 lines GO