Documentation
¶
Overview ¶
Package flow 实现垂类路由:Host 根据事实决定下一个调哪个子代理做什么。
设计原则:
- Route 是纯函数:输入 State,输出 *Instruction。无 IO、无 Store 调用,可单测。
- State 由 LoadState(非纯)从 Store 构造,一次性把路由需要的事实读齐。
- 返回 nil 是合法的:表示"裁定场景,让 Coordinator LLM 自主决策"。
Router 覆盖的是"查表型"决策(每章下一步、弧末后处理、队列驱动), 不覆盖"语义理解型"决策(选规划师、处理用户 Steer、输出总结)。
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func FormatMessage ¶
func FormatMessage(i *Instruction) string
FormatMessage 把 Instruction 格式化为发给 Coordinator 的用户消息。 批量指令(Batch 非空)渲染为"单次 subagent(tasks=[...])"并行话术; 单派指令保持原 subagent(agent, task) 话术。
func PendingCandidates ¶
PendingCandidates 返回本章尚未就绪且未弃权的 persona(保持 Personas 顺序)。 dispatcher 与 routeContest 共用,避免"待补候选"判定逻辑漂移。
func PromoteIfNeeded ¶
func PromoteIfNeeded(store *storepkg.Store, cfg ContestConfig, chapter int) bool
PromoteIfNeeded 在"有 verdict 且未提升"时执行中选稿提升,返回是否发生了提升。 纯 store 操作,幂等:已提升或无 verdict 时返回 false。
Types ¶
type ContestConfig ¶
type ContestConfig struct {
Personas []string // persona slug,顺序即写作顺序;len<2 视为未启用
Concurrency bool // 候选生成是否并发
Synopsis bool // 两段式:候选只写梗概+开头,中选后写全章
}
ContestConfig 是 LoadStateWithContest 需要的竞稿静态配置(来自 bootstrap.Config 解析后的 slug 列表)。
type Dispatcher ¶
type Dispatcher struct {
// contains filtered or unexported fields
}
Dispatcher 订阅 Coordinator 事件,在子代理返回时计算路由并下达 Host 指令。
生命周期:Attach 返回一个 detach 函数;关闭 Host 时调用释放订阅。
func NewDispatcher ¶
func NewDispatcher(coordinator *agentcore.Agent, store *storepkg.Store) *Dispatcher
NewDispatcher 创建 Dispatcher。使用前需调用 Attach 订阅事件。
func (*Dispatcher) Attach ¶
func (d *Dispatcher) Attach() func()
Attach 订阅 Coordinator 事件;返回的函数在关闭时调用以解绑。
func (*Dispatcher) Dispatch ¶
func (d *Dispatcher) Dispatch()
Dispatch 立即计算路由并下达指令;可被 Host 在特殊时机(如 Resume 后)主动调用。
func (*Dispatcher) Enable ¶
func (d *Dispatcher) Enable()
Enable 打开路由派发;关闭时 EventToolExecEnd 到达不会发 FollowUp。 Host 在 Start/Resume 完成首条 prompt 之后启用,避免与启动流程冲突。
func (*Dispatcher) ResetDedupe ¶
func (d *Dispatcher) ResetDedupe()
ResetDedupe 清空去重缓存与无进展状态。Resume / 新 Start 时 Host 调用。
func (*Dispatcher) SetContest ¶
func (d *Dispatcher) SetContest(cfg ContestConfig)
SetContest 注入竞稿配置;Host 在启用竞稿时调用。
func (*Dispatcher) SetGate ¶ added in v0.7.0
func (d *Dispatcher) SetGate(gate func() bool)
SetGate 注入派发门禁;Host 在启用预算控制时装配期调用一次。
type Instruction ¶
type Instruction struct {
Agent string // architect_long / architect_short / writer / editor;批量时为 ""
Task string // 给子代理的任务描述
Reason string // 给 Coordinator 看的理由(可选,方便调试与日志)
Chapter int // writer 任务涉及的章节号;0 表示不涉及
Batch []SubTask // 非空 = parallel 批量指令;空 = 原单派语义
}
Instruction 指示 Host 下一步要求 Coordinator 调用的子代理与任务。
func Route ¶
func Route(s State) *Instruction
Route 根据事实返回下一步指令;返回 nil 表示让 Coordinator LLM 自主裁定。
决策优先级(互斥,自上而下匹配第一个):
- Phase=Complete → nil(LLM 输出总结)
- Phase!=Writing → nil(LLM 裁定规划师选型 / 规划补齐)
- PendingRewrites 非空 → writer 按队列重写/打磨
- Flow=Reviewing → nil(editor 刚保存 review,verdict 分叉由工具层处理)
- Flow=Steering → nil(用户干预处理中)
- 弧末评审缺失 → editor(arc review)
- 弧末评审有但弧摘要缺失 → editor(arc summary)
- 卷末弧摘要有但卷摘要缺失 → editor(volume summary)
- 下一弧是骨架 → architect_long(expand_arc)
10. 卷末需决策下一卷 → architect_long(append_volume / complete_book) 11. 竞稿章(启用且 ContestChapter>0)→ routeContest 四步子状态机 12. 其它 → writer(写 next_chapter)
type State ¶
type State struct {
Progress *domain.Progress
// 上一个已完成章节(Progress.CompletedChapters 末尾);为 0 表示尚未开始写作。
LastCompleted int
// 上一章的弧边界信息;IsArcEnd=false 时其他字段无意义。
// 当 LastCompleted=0 或非 Layered 模式时应为 nil。
ArcBoundary *storepkg.ArcBoundary
// 弧末后处理的三个事实:评审 / 弧摘要 / 卷摘要是否已完成。
HasArcReview bool
HasArcSummary bool
HasVolumeSummary bool
// 基础设定缺项(规划阶段的补齐信号)。
FoundationMissing []string
// 竞稿事实(ContestEnabled=false 时其余字段无意义)。
ContestEnabled bool // 是否启用多人格竞稿
Personas []string // persona slug 列表,顺序即写作顺序
ContestChapter int // 当前竞稿目标章(= NextChapter),0 表示不适用
CandidatesReady map[string]bool // 各 persona 候选稿是否到位
HasVerdict bool // 本章是否已有裁定
VerdictWinner string // 中选 persona slug
IsPromoted bool // 中选稿是否已提升为正式 draft.md
VerdictRevisionNotes string // 中选稿的修改意见(来自 verdict,供润色 writer 参考)
ContestConcurrent bool // 候选生成是否并发(true=一次 parallel 批量派发)
ContestSynopsis bool // 两段式:候选为梗概+开头,终稿阶段才写全章
// Abandoned: nil 表示读取失败(已降级处理),空 map 表示本章无弃权
Abandoned map[string]bool // 本章已弃权 persona slug(并发失败收敛)
}
State 是 Route 的输入:所有事实必须在此显式声明,禁止 Route 内部读 Store。
func LoadState ¶
LoadState 从 Store 读取 Route 所需的全部事实。 这是路由的"IO 边界":所有读取集中在这里,Route 保持纯。 读取失败按保守默认填充(has*=false, boundary=nil),让 Router 倾向重派而非跳过。
func LoadStateWithContest ¶
func LoadStateWithContest(store *storepkg.Store, cfg ContestConfig) State
LoadStateWithContest 在 LoadState 基础上补齐竞稿事实。 非竞稿场景(cfg.Personas<2)等价于原 LoadState。