package orchestration import ( "context" "fmt" "git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/loop" ) // 本文件持有 design/22 §8-2 里「派出去的子代理以目标角色身份运行」那一半:带目标 // 角色派发的子代理必须以那个角色的指令作答、使用那个角色的记忆作用域,而本进程跑 // 不了的角色必须明确报错,不得静默降级为默认角色。 // // 解析本身留在循环里(internal/runtime/loop/persona.go):每一处按角色作用域的读取 // —— 提示词(agent 池)、记忆命名空间、情绪、思考旋钮 —— 都派生自会话 env 的 // PersonaID 这一个输入,因此四者不可能互相矛盾。编排层因此只有两件事要做:校验 // id,并把它盖到子代理的运行上下文上。两者都不碰身份车道(ActorEnv / MemWritable), // 那条车道由渠道层从结构上决定,从来不是角色的分内事(项目红线:身份识别靠元数据)。 // PersonaKnown 报告 personaID 是否为本进程能以自身指令运行的角色 // (Options.PersonaExists)。空 id 平凡已知:调用方没有指名任何角色,即既有的单角色 // 派发。resolver 为 nil 时所有具名角色都算未知,因此指名角色的派发会失败,而不是 // 悄悄按默认角色运行。 func (s *Scheduler) PersonaKnown(personaID string) bool { return personaID == "" || (s.personaExists != nil && s.personaExists(personaID)) } // effectiveRole 返回记在子代理上的绑定角色。被派发的 persona 就是绑定本身(子代理 // 以该角色身份作答),因此它填补空的 RoleID;指名了不存在的 persona 的显式 RoleID // 则保持调用方所设。记录下来的角色正是进度事件与 ws subagent_event 帧所报告的内容, // 所以前端不会看到「以 yuki 身份运行却角色为空」的子代理。 func effectiveRole(spec AgentSpec) string { if spec.RoleID == "" { return spec.PersonaID } return spec.RoleID } // checkPersona 拒绝本进程跑不了的角色,包装 ErrUnknownPersona,使调用方能以 // errors.Is 归类。 func (s *Scheduler) checkPersona(personaID string) error { if s.PersonaKnown(personaID) { return nil } return fmt.Errorf("orchestration: spawn: persona %q: %w", personaID, ErrUnknownPersona) } // CheckPersonas 在整批派发前校验每个 spec 的目标角色,因此一个未知 id 会拒绝整批 // 派发,而不会留下批次里先建好的、结果永远不上报的子代理。派发工具在解码参数后立即 // 调用它:那时 id 已知,但什么都还没启动。 func (s *Scheduler) CheckPersonas(specs []AgentSpec) error { for _, spec := range specs { if err := s.checkPersona(spec.PersonaID); err != nil { return err } } return nil } // withPersonaEnv 返回把目标角色盖到会话 env 上的 ctx,使循环为子代理运行的每一步 // 解析该角色的提示词与记忆作用域。env 的其余部分(身份车道与记忆写入门)原样拷贝 // —— 角色决定她怎么回答,绝不决定她能碰什么。空 id 返回未改动的 ctx,因此无角色 // 的派发同之前一样继续继承派发回合的 env。 func withPersonaEnv(ctx context.Context, personaID string) context.Context { if personaID == "" { return ctx } env := loop.SessionEnvFrom(ctx) env.PersonaID = personaID return loop.WithSessionEnv(ctx, env) }