Files
Cyrene_v2/internal/runtime/orchestration/persona.go
T
AskaEth eb1828ee7a
CI / Backend (build / vet / test / cross-compile) (push) Has been cancelled
CI / Frontend (tsc + vite build) (push) Has been cancelled
docs(comments): 注释中文化 · internal/runtime/orchestration(29 文件,纯替换)
- 只翻注释/文档字符串:剥离注释后代码行逐字节不变(机械校验只剩允许的行尾注释形态)
- 裁决编号与 design 节号(02.4.3 / 11.4.2 / design/05 §9 等)逐字保留
- 复核:go build 绿;orchestration 及其子包(audit/comm)测试绿;gofmt 干净
2026-10-04 13:30:04 +08:00

72 lines
3.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
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)
}