docs(cyrene): cmd/cyrene 存量英文注释中文化(22 个非测试文件,仅注释)
- 四组并行完成:main/wire*.go、wire_capacity|channels|runtime、channels|persona_*|emotion|observability、 voice|plugins|stream|skills|vision|subagent_tool|extractor|mcp|sessionread_tool|terminal_tool。 - 机械校验(git diff -U0 去 // 行与空行)仅剩 wire_frontend.go:84 一处行尾注释:代码前缀 「\ta.gw = gw 」经 cat -A 与 HEAD 逐字节比对一致(allow 清单已声明)。 - 验收:隔离 worktree(HEAD + 本批 patch)go build/vet 绿、全树 58 包 ok、 linux/amd64 + darwin/arm64 交叉编译绿;gofmt -l 干净。 - 备注:整树两次红均为负载敏感 flake(backthink / orchestration 的 timeout 类用例单独 -count=20 全过)。
This commit is contained in:
1 parent
5c2189efb0
commit
52f08dc343
22 files changed
+455
-586
No files matched your search
@@ -8,22 +8,19 @@ import (
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/tool"
|
||||
)
|
||||
|
||||
// This file builds the per-role agent pool (design/22 §4.2 方案 A). An
|
||||
// agent.Agent's instructions are immutable after construction, so "the session's
|
||||
// role decides the system prompt" is implemented as one agent per role, all
|
||||
// sharing the same dispatcher, guardrail pipeline, model adapter and options —
|
||||
// only the instruction string differs. The loop picks the pool entry for the
|
||||
// turn's role on every step (internal/runtime/loop/persona.go), so a role switch
|
||||
// takes effect on the next turn without rebuilding the loop.
|
||||
// 本文件构建按角色的 agent 池(design/22 §4.2 方案 A)。agent.Agent 的指令在构造
|
||||
// 之后不可变,因此「会话的角色决定 system 提示」被实现为每个角色一个 agent:它们
|
||||
// 共享同一个 dispatcher、guardrail 流水线、模型适配器与选项 —— 只有指令字符串不同。
|
||||
// 循环在每一步为当轮角色挑选池中条目(internal/runtime/loop/persona.go),因此角色
|
||||
// 切换在下一轮即生效,无需重建循环。
|
||||
//
|
||||
// Requirements from design/22 §5: prompt, memory, emotion and thinking must all
|
||||
// be resolved from the same role. The pool owns the prompt; the loop owns the
|
||||
// other three (personaFor / knobsFor), so a turn can never mix two roles.
|
||||
// design/22 §5 的要求:提示、记忆、情绪与 thinking 必须全部由同一个角色解析。
|
||||
// 池拥有提示,循环拥有另外三者(personaFor / knobsFor),因此一轮绝不会混用两个
|
||||
// 角色。
|
||||
|
||||
// personaAgentPool returns the per-role agent pool plus the agent to run turns
|
||||
// with: the pooled agent for the default role when the pool has one, otherwise the
|
||||
// caller's fallback agent, so a deployment with no registered character keeps
|
||||
// exactly the pre-multi-character single agent.
|
||||
// personaAgentPool 返回按角色的 agent 池,以及用来跑轮次的 agent:池中有默认角色时
|
||||
// 用池里的那个,否则用调用方的兜底 agent,因此未注册任何角色的部署仍保持与多角色
|
||||
// 之前完全一致的单 agent 形态。
|
||||
func (a *app) personaAgentPool(llm *model.RuntimeLLM, dispatcher *tool.Dispatcher, guards *guardrail.Pipeline, fallback *agent.Agent) (map[string]*agent.Agent, *agent.Agent) {
|
||||
pool := a.buildPersonaAgents(llm, dispatcher, guards)
|
||||
if pooled, ok := pool[a.defaultPersonaID()]; ok {
|
||||
@@ -32,22 +29,19 @@ func (a *app) personaAgentPool(llm *model.RuntimeLLM, dispatcher *tool.Dispatche
|
||||
return pool, fallback
|
||||
}
|
||||
|
||||
// buildPersonaAgents returns the role → agent pool: every registered character's
|
||||
// persona gets an agent carrying that persona's system instruction
|
||||
// (instructionsFromPersona, the very same assembly point as the default agent —
|
||||
// see personaInstructions), design/01 §2.2. It returns an empty map when no
|
||||
// persona is registered, so the loop keeps its single default agent.
|
||||
// buildPersonaAgents 返回「角色 → agent」池:每个已注册角色对应的 persona 都得到
|
||||
// 一个携带该 persona system 指令的 agent(instructionsFromPersona,与默认 agent
|
||||
// 是同一个装配点 —— 见 personaInstructions),design/01 §2.2。未注册 persona 时
|
||||
// 返回空 map,循环便保持其单一默认 agent。
|
||||
//
|
||||
// 池里的指令是**静态**的,因此主人身份说明书不在其中:那段知识按会话注入
|
||||
// (loop.Options.PersonaKnowledgeFor),否则它会跟着每个角色进入群聊与
|
||||
// 陌生人私聊(design/11 §0 红线)。
|
||||
//
|
||||
// Only personas reachable through a registered character are pooled: a character
|
||||
// is the selectable unit (1 character ↔ 1 persona), so a persona with no character
|
||||
// can never be bound to a session. A session bound to an unknown id therefore
|
||||
// falls back to the default agent, and its memory scope still follows the bound
|
||||
// id — a stale binding degrades to the default prompt rather than failing the
|
||||
// turn.
|
||||
// 只有通过已注册角色可达的 persona 才入池:角色才是可选单位(1 角色 ↔ 1 persona),
|
||||
// 因此没有角色的 persona 永远无法绑定到会话。绑定到未知 id 的会话于是退回默认
|
||||
// agent,而其记忆作用域仍跟随所绑定的 id —— 过期的绑定退化为默认提示,而不是让
|
||||
// 该轮失败。
|
||||
func (a *app) buildPersonaAgents(llm *model.RuntimeLLM, dispatcher *tool.Dispatcher, guards *guardrail.Pipeline) map[string]*agent.Agent {
|
||||
log := logger.WithSource(a.log, "cmd/cyrene")
|
||||
pool := make(map[string]*agent.Agent, a.personas.CountPersonas())
|
||||
@@ -74,13 +68,10 @@ func (a *app) buildPersonaAgents(llm *model.RuntimeLLM, dispatcher *tool.Dispatc
|
||||
return pool
|
||||
}
|
||||
|
||||
// personaExists returns the resolver the orchestration layer validates a dispatched
|
||||
// sub-agent's target role with (design/22 §8-2). A role is dispatchable exactly when
|
||||
// the pool has an agent for it, which is precisely the condition under which the loop
|
||||
// would answer with that role's instructions. Every other answer — an unregistered
|
||||
// persona, a persona with no character, an empty pool — makes the dispatch fail with
|
||||
// orchestration.ErrUnknownPersona instead of quietly running the sub-agent as the
|
||||
// default role.
|
||||
// personaExists 返回编排层用来校验被派发的子代理目标角色的解析器(design/22 §8-2)。
|
||||
// 某角色可派发,当且仅当池中有它的 agent,而这正是循环会用该角色指令作答的条件。
|
||||
// 其他任何情况 —— 未注册的 persona、没有角色的 persona、空池 —— 都会让派发以
|
||||
// orchestration.ErrUnknownPersona 失败,而不是悄悄按默认角色运行子代理。
|
||||
func personaExists(pool map[string]*agent.Agent) func(personaID string) bool {
|
||||
return func(personaID string) bool {
|
||||
_, ok := pool[personaID]
|
||||
|
||||
Reference in new issue
Block a user