package main import ( "time" "git.yeij.top/AskaEth/Cyrene_v2/internal/logger" "git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/orchestration" ) // defaultSubagentTimeout 在别处都未配置时,约束单个子代理的整轮运行。 // DevDocs/design/05-子代理.md §7 要求有超时与防失控上限;调度器两者都已实现 // (PerAgentTimeout、Abort/CancelAll),因此生产必须给出一个值,否则每代理超时 // 形同虚设(调度器里的 0 表示「无超时」)。该值刻意给得宽松 —— 子代理与任何循环 // 一样最多跑 8 轮工具 —— 并且是 SUBAGENT_TIMEOUT_SEC 之后的兜底(裁决 02.4.4: // 默认 10min,可配置;subagentToolTimeout 解析出生效值)。 const defaultSubagentTimeout = 10 * time.Minute // subagentToolTimeout 解析分派工具的默认子代理超时:SUBAGENT_TIMEOUT_SEC 为正时 // 以它为准,否则采用代码里的 10 分钟默认值(design/05 §7 裁决 02.4.4)。每次分派 // 传入的 timeout_seconds 参数仍会在工具层按次覆盖此值。 func (a *app) subagentToolTimeout() time.Duration { if a.cfg != nil && a.cfg.Subagent.TimeoutSec > 0 { return time.Duration(a.cfg.Subagent.TimeoutSec) * time.Second } return defaultSubagentTimeout } // wireSubagentTool 向分发器注册子代理分派工具,让 agent 在运行时终于能触达编排层 // (在此之前 (*orchestration.Scheduler).Spawn 没有生产调用方,design/05 只是库)。 // // 该能力以默认的可达性标记(两者皆 false)注册,从而保持仅主人可用:design/11 §3 的 // 策略引擎会对群聊/陌生人会话隐藏其 schema,循环的安全门也会在那里拒绝调用。 // design/05 §6/§7 未给群聊/陌生人分派后台 agent 的许可,且能生成子代理属于重操作, // 因此刻意选择安全默认值,而不是让它被意外开启。 func (a *app) wireSubagentTool() { log := logger.WithSource(a.log, "cmd/cyrene") if a.scheduler == nil { log.Warn("sub-agent tool skipped: no scheduler") return } spawner := orchestration.NewSpawnTool(a.scheduler, orchestration.WithSpawnLogger(a.log), orchestration.WithSpawnTimeout(a.subagentToolTimeout())) if err := a.dispatcher.Register(spawner); err != nil { log.Warn("sub-agent tool register skipped", "error", err) return } log.Info("sub-agent tool registered", "tool", orchestration.SpawnToolName, "owner_only", true) }