package orchestration import ( "context" "sync" "testing" "git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/loop" "git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/model" ) // dispatchTaskRunner 记录每个子代理运行的 context(含其中挂的派发任务标记)。 type dispatchTaskRunner struct { mu sync.Mutex ctx []context.Context } func (r *dispatchTaskRunner) Run(ctx context.Context, _ string, _ []model.Message) (*loop.Result, error) { r.mu.Lock() r.ctx = append(r.ctx, ctx) r.mu.Unlock() return &loop.Result{Text: "ok", Steps: 1, StopReason: "stop"}, nil } func (r *dispatchTaskRunner) last() context.Context { r.mu.Lock() defer r.mu.Unlock() return r.ctx[len(r.ctx)-1] } // TestSubagentTaskRidesRunContext 锁定口径 A 的结构化来源:编排层在驱动子代理 Run // 之前把**派给它的任务目标**挂到运行 context 上,代审判定器据此识别「这次调用由 // 子代理发起」并拿到判越界所需的任务。缺失这条挂载 ⇒ 子代理的敏感调用会静默绕过 // 实质判定(本用例就是那个缺口的第一道闸)。 func TestSubagentTaskRidesRunContext(t *testing.T) { t.Parallel() s := newScheduler(t, Options{MaxParallel: 1}) m := &dispatchTaskRunner{} s.runner = m sub, err := s.Spawn(context.Background(), AgentSpec{Goal: "整理 data/ 下的导出文件"}) if err != nil { t.Fatalf("Spawn: %v", err) } if _, werr := s.Wait(context.Background(), []string{sub.ID}); werr != nil { t.Fatalf("Wait: %v", werr) } got, ok := loop.SubagentTaskFrom(m.last()) if !ok { t.Fatal("子代理的运行 context 上没有派发任务标记(代审的越界判定将无从触发)") } if got != "整理 data/ 下的导出文件" { t.Fatalf("派发任务 = %q, want 派给该子代理的任务目标", got) } }