57 lines
1.8 KiB
Go
57 lines
1.8 KiB
Go
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)
|
|
}
|
|
}
|