- 只翻注释/文档字符串:剥离注释后代码行逐字节不变(机械校验只剩允许的行尾注释形态) - 裁决编号与 design 节号(02.4.3 / 11.4.2 / design/05 §9 等)逐字保留 - 复核:go build 绿;orchestration 及其子包(audit/comm)测试绿;gofmt 干净
125 lines
5.2 KiB
Go
125 lines
5.2 KiB
Go
package orchestration
|
||
|
||
import (
|
||
"log/slog"
|
||
"time"
|
||
|
||
"git.yeij.top/AskaEth/Cyrene_v2/internal/bus"
|
||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/loop"
|
||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/memory"
|
||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/orchestration/audit"
|
||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/orchestration/comm"
|
||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/trace"
|
||
)
|
||
|
||
// 编排层的默认值。
|
||
const (
|
||
// DefaultMaxParallel 是 Options.MaxParallel 为非正数时同时运行的子代理
|
||
// 数量上限。
|
||
DefaultMaxParallel = 4
|
||
|
||
// defaultAgentID 是 Options.AgentID 为空、且必须由 Bus 构建探针时所用的
|
||
// comm 探针身份。
|
||
defaultAgentID = "orchestrator"
|
||
)
|
||
|
||
// Options 配置由 New 构建的 Scheduler。所有字段都可选;每个为 nil 的依赖都优雅
|
||
// 降级(缺 Loop 使子代理快速失败,缺 Comm 跳过进度事件,缺 Approver 使 Approve
|
||
// 报错,等等)。
|
||
type Options struct {
|
||
// MaxParallel 限制同时执行的子代理数量。超出的子代理排队直到有空位。
|
||
// 非正数则选用 DefaultMaxParallel(4)。
|
||
MaxParallel int
|
||
|
||
// PerAgentTimeout 约束每个子代理的运行时限。超时后该子代理被中止
|
||
// (状态 aborted)。非正数表示不设时限。
|
||
PerAgentTimeout time.Duration
|
||
|
||
// Loop 是执行模板:用于运行每个子代理的 *loop.Loop。它必须能安全地并发调用
|
||
// Run(如 loop.Loop 自身文档所述);模板的 agent/tools/guardrails/persona
|
||
// 适用于每个子代理。为 nil 时子代理以 ErrNoRunner 快速失败。
|
||
Loop *loop.Loop
|
||
|
||
// Bus 是进程内事件总线,用于发布进度事件;Comm 为 nil 时也由它构建默认
|
||
// comm 探针。为 nil 时不发布任何事件。
|
||
Bus bus.Bus
|
||
|
||
// Comm 是用于发布进度事件的 comm 探针。为 nil 时,用 Bus(Bus 非 nil 时)
|
||
// 构建一个绑定到 AgentID 的探针。
|
||
Comm *comm.Probe
|
||
|
||
// Memory 是 SinkMemory 所用的长期记忆存储。可选。
|
||
Memory *memory.Store
|
||
|
||
// Tracer 为每次运行发射一个子代理 span(kind subagent)。可选。
|
||
Tracer *trace.Tracer
|
||
|
||
// Flow 非 nil 时接收子代理 span 的状态转移,使派生出的分支出现在
|
||
// AgentSpec.ParentSession 所指会话的流程图里(design/19 §2)。
|
||
// *loop.FlowPublisher 是生产实现。可选:sink 为 nil 时子代理分支不被可视化
|
||
// (子代理自身的内部 span 仍会经循环的 flow 分支折进父图)。
|
||
Flow FlowSpanSink
|
||
|
||
// Approver 记录由 Approve 触发的敏感操作「代审」。策略判断属于上层。可选。
|
||
Approver *audit.Approver
|
||
|
||
// PersonaExists 报告某个角色 id 能否以自身指令运行,即 Loop 背后的按角色
|
||
// agent 池(loop.Options.Agents)里是否有它的条目(design/22 §8-2)。它把守
|
||
// AgentSpec.PersonaID:指名了一个它返回 false 的 id 的派发会被拒绝并返回
|
||
// ErrUnknownPersona,而不是按默认角色的提示词运行。为 nil 意味着「本部署不认识
|
||
// 任何角色」,因此指名角色的派发同样被拒 —— 关键是绝不悄悄替调用方做决定。
|
||
// 省略 persona 的派发不受它影响。
|
||
PersonaExists func(personaID string) bool
|
||
|
||
// Logger 是基础 logger。为 nil 时替换为标注了来源 "orchestration" 的
|
||
// 丢弃式 logger。
|
||
Logger *slog.Logger
|
||
|
||
// AgentID 是 comm 探针身份。为空且必须由 Bus 构建探针时,使用
|
||
// "orchestrator"。
|
||
AgentID string
|
||
}
|
||
|
||
// FlowSpanSink 把一个 span 的状态转移折进会话的实时流程图,使实时可视化展示在飞的
|
||
// 工作(design/19 §1)。*loop.FlowPublisher 是生产实现;测试替换为捕获式假实现。
|
||
// 该接口让编排层除了已有的循环模板之外,不必再依赖那个具体发布器。
|
||
type FlowSpanSink interface {
|
||
// SpanStarted 为一个刚刚开始的 span 登记运行中的占位节点。
|
||
SpanStarted(sessionID string, sp *trace.Span)
|
||
// SpanFinished 把一个刚结束的 span 折进会话图。
|
||
SpanFinished(sessionID string, sp *trace.Span)
|
||
}
|
||
|
||
// wrapLoop 把 *loop.Loop 适配成 runner 接口;模板为 nil 时替换为空操作 runner
|
||
// (快速失败)。
|
||
func wrapLoop(l *loop.Loop) runner {
|
||
if l == nil {
|
||
return noopRunner{}
|
||
}
|
||
return l
|
||
}
|
||
|
||
// scopedRunner 挑选执行 sub 的 runner:没有工具白名单时按原样运行已配置的模板
|
||
// (缺省全开,继承主 agent 全量工具集);有白名单时,为 *loop.Loop 模板经
|
||
// WithToolWhitelist 派生出只放行所列工具的新模板(design/05 §7 裁决 02.4.1)。
|
||
// 非 loop 的 runner(测试注入的 mock)原样返回 —— 白名单仍随运行上下文传递,它可经
|
||
// loop.ToolWhitelistFrom 自行读取。
|
||
func (s *Scheduler) scopedRunner(sub *SubAgent) runner {
|
||
if len(sub.ToolWhitelist) == 0 {
|
||
return s.runner
|
||
}
|
||
if lp, ok := s.runner.(*loop.Loop); ok {
|
||
return lp.WithToolWhitelist(sub.ToolWhitelist)
|
||
}
|
||
return s.runner
|
||
}
|
||
|
||
// effectiveTimeout 解析某个子代理运行时所受的时限:正的按调用覆盖优先;否则套用
|
||
// 调度器的 PerAgentTimeout(非正 = 无期限)。
|
||
func effectiveTimeout(override, schedulerDefault time.Duration) time.Duration {
|
||
if override > 0 {
|
||
return override
|
||
}
|
||
return schedulerDefault
|
||
}
|