design/22 §8-2(主人 2026-10-03 拍板):跨角色协作 = 把其他角色以子代理形式派出去,
该子代理以目标角色的 instructions 运行、并按目标角色的记忆作用域读写。
- AgentSpec / SubAgent / SubAgentResult 新增 PersonaID;Options.PersonaExists 作角色解析器
- scheduler:派发前校验角色(ErrUnknownPersona),批量 all-or-nothing;
run ctx 经 withPersonaEnv 只覆盖 SessionEnv.PersonaID —— ActorEnv/MemWritable 原样复制
(身份识别靠 channel 元数据,persona 决定她怎么答、不决定她能碰什么:项目红线)
- 记忆归属键改为 PersonaID 优先(回落 RoleID)→ 替班者写的是目标角色的记忆域
- spawntool:schema 顶层与 tasks[] 新增可选 persona;省略 = 与旧行为逐字节一致
- 分支根节点新增 props.persona(可观测性);SinkMemory 移入 memory.go(守 500 行红线)
- 组合根:personaExists(agent 池);cmd/cyrene/wire.go +5 行
契约:Docs/api-client.md -> v0.47(graph_update 新增可选 props.persona,纯增量)
验证:go build/vet ./... 绿;internal/runtime/orchestration + cmd/cyrene 测试绿;
go test -race ./internal/runtime/orchestration -run Persona 绿;
linux/amd64 + darwin/arm64 交叉编译绿
变异验证:① 目标角色换回父/默认角色(3 处断言 FAIL)② 关调度器侧角色校验 ③ 关工具侧预检
98 lines
3.0 KiB
Go
98 lines
3.0 KiB
Go
package orchestration
|
|
|
|
import (
|
|
"fmt"
|
|
"time"
|
|
|
|
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/loop"
|
|
)
|
|
|
|
// SubAgentResult is a point-in-time snapshot of a SubAgent. It is used both as
|
|
// the per-sub-agent entry in MergedResult and as the return value of
|
|
// (*SubAgent).Snapshot for monitoring.
|
|
type SubAgentResult struct {
|
|
// ID is the sub-agent id.
|
|
ID string
|
|
// Goal is the sub-agent's objective.
|
|
Goal string
|
|
// RoleID is the bound role/persona.
|
|
RoleID string
|
|
// PersonaID is the target role the sub-agent runs as (blank = the spawning
|
|
// turn's role), whose instructions and memory scope its run used (design/22 §8-2).
|
|
PersonaID string
|
|
// Mode is the bound behavior mode.
|
|
Mode string
|
|
// AttachInfo is the supplied attachment text.
|
|
AttachInfo string
|
|
// Status is the terminal (or current) status.
|
|
Status Status
|
|
// Summary is the execution summary written on finalization.
|
|
Summary string
|
|
// Text is the loop result text on a successful run.
|
|
Text string
|
|
// Steps is the number of loop steps executed on a successful run.
|
|
Steps int
|
|
// Err is the error that ended a failed/aborted run (nil on success).
|
|
Err error
|
|
// StartedAt is when the sub-agent began running.
|
|
StartedAt time.Time
|
|
// FinishedAt is when the sub-agent finalized.
|
|
FinishedAt time.Time
|
|
}
|
|
|
|
// MergedResult aggregates the outcomes of every spawned sub-agent, produced by
|
|
// (*Scheduler).Join.
|
|
type MergedResult struct {
|
|
// Agents holds one entry per spawned sub-agent, in spawn order.
|
|
Agents []SubAgentResult
|
|
// Total is the number of spawned sub-agents.
|
|
Total int
|
|
// Succeeded is how many sub-agents finished with StatusDone.
|
|
Succeeded int
|
|
// Failed is how many sub-agents finished with StatusFailed.
|
|
Failed int
|
|
// Aborted is how many sub-agents finished with StatusAborted.
|
|
Aborted int
|
|
// Summary is a one-line aggregate summary of all sub-agents.
|
|
Summary string
|
|
}
|
|
|
|
// summaryTextMax caps how many runes of the result text appear in a summary.
|
|
const summaryTextMax = 80
|
|
|
|
// doneSummary builds the execution summary written when a sub-agent succeeds.
|
|
func doneSummary(res *loop.Result) string {
|
|
if res == nil {
|
|
return "完成"
|
|
}
|
|
text := compactText(res.Text, summaryTextMax)
|
|
if res.StopReason != "" {
|
|
return fmt.Sprintf("完成 (%s, 步骤=%d): %s", res.StopReason, res.Steps, text)
|
|
}
|
|
return fmt.Sprintf("完成 (步骤=%d): %s", res.Steps, text)
|
|
}
|
|
|
|
// failedSummary builds the summary written when a sub-agent fails.
|
|
func failedSummary(err error) string {
|
|
if err == nil {
|
|
return "失败"
|
|
}
|
|
return "失败: " + err.Error()
|
|
}
|
|
|
|
// canceledSummary builds the summary written when a sub-agent is aborted.
|
|
func canceledSummary() string {
|
|
return "中止: 已取消"
|
|
}
|
|
|
|
// timeoutSummary builds the summary written when a sub-agent times out.
|
|
func timeoutSummary(d time.Duration) string {
|
|
return fmt.Sprintf("中止: 超时 (%s)", d)
|
|
}
|
|
|
|
// summarizeMerged produces the one-line aggregate summary of a merged result.
|
|
func summarizeMerged(r *MergedResult) string {
|
|
return fmt.Sprintf("子代理汇总: 共 %d 个, %d 成功, %d 失败, %d 中止",
|
|
r.Total, r.Succeeded, r.Failed, r.Aborted)
|
|
}
|