feat(cyrene,config,loop): 护栏/压缩/身份知识三条落地(P0-5/P0-10/P0-11)+ 身份注入收窄到主人会话
- P0-5 护栏不再是空壳:挂 WithSensitiveInfo(阻断) + 长度上限(输入 262144 / 输出 65536 字符,依据=
组装完成的请求体量级与「不误伤正常对话」) + 关键词**仅在配置时**挂;正常对话有用例证明放行
- P0-11 上下文压缩默认启用:CONTEXT_MAX_TOKENS 默认 32768(=loop.DefaultMaxContextTokens,两常量由测试锁死),
0/负 = 关闭(行为退回接线前);长对话真压缩且摘要消息进请求首位、最近一轮保留
- P0-10 身份说明书(owner.yaml identityFile)注入人格上下文,并且**收窄为仅主人会话**:
· 新增最小钩子 loop.Options.PersonaKnowledgeFor(env):**按该轮会话环境**解析(不看提示词、不看会话 id),
块只进每轮视图、**不进 messages**(不进 checkpoint、不进记忆提取面)
· 开关 OWNER_IDENTITY_INJECTION:owner_only(默认) / always(仅自测) / off;非法值与读不动 → WARN + 回退默认(不静默)
· **顺手关掉第二条同型泄漏**:channelbridge 群聊参与度判定器的 PersonaPrompt 此前带身份正文 ⇒ 现改为纯人格指令
· 回归:缺文件/目录/未配置逐字节等于旧输出;静态指令与角色池 Instructions() 全不含正文;
文件里点名的陌生账号仍 IsOwner==false(身份知识绝不参与权限判定)
- 复核:build/vet 绿 + cmd/config/loop 包测试绿;四类断言(主人含 / **群聊与陌生人不含** / always·off 两档 /
回归不变)+ 4 条变异反证(含把判定改成恒真 → 提示词里真的出现身份说明书)均已还原
- 未做(登记):knowledge 块启动时读一次(改文件需重启);`.env.example` 的 OWNER_IDENTITY_INJECTION 行随后补;
`internal/user/owner.go` 注释与 design/01 §2.2、design/11 §0 待同步
This commit is contained in:
1 parent
19f296a2ab
commit
da3a386daf
18 files changed
+1758
-81
No files matched your search
+36
-25
@@ -15,7 +15,6 @@ import (
|
||||
personareg "git.yeij.top/AskaEth/Cyrene_v2/internal/persona/registry"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/agent"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/embedding"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/guardrail"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/history"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/loop"
|
||||
"git.yeij.top/AskaEth/Cyrene_v2/internal/runtime/memory"
|
||||
@@ -148,7 +147,9 @@ func (a *app) wireRuntime() error {
|
||||
}
|
||||
a.wireVision()
|
||||
|
||||
guards := guardrail.New()
|
||||
// 默认护栏策略在 buildGuardrailPipeline 里集中定义(敏感信息阻断 +
|
||||
// 长度上限 + 仅当配置提供时的关键词表,见 wire_guardrail.go)。
|
||||
guards := a.buildGuardrailPipeline()
|
||||
instructions := a.defaultInstructions()
|
||||
// 默认角色的 agent 也要绑它自己的 persona 视图:models.json 的 personaModels /
|
||||
// personaProviders 可能给默认角色单独指定模型或提供商,用裸栈会漏掉这一层
|
||||
@@ -240,26 +241,34 @@ func (a *app) wireRuntime() error {
|
||||
approvalGate := a.buildApprovalGate(approver)
|
||||
|
||||
a.loop = loop.New(loop.Options{
|
||||
Agent: defaultAgent,
|
||||
Agents: agents,
|
||||
Tools: a.dispatcher,
|
||||
Capacity: capDecider,
|
||||
OnCapacity: a.onCapacity,
|
||||
OnAudit: a.onToolAudit,
|
||||
OnTurnEnd: a.onTurnEnd,
|
||||
Memory: store,
|
||||
Retriever: a.retriever,
|
||||
Extractor: a.buildMemoryExtractor(),
|
||||
Checkpoint: checkpoint,
|
||||
Tracer: tracer,
|
||||
Flow: flowPub,
|
||||
Guards: guards,
|
||||
PersonaID: personaID,
|
||||
PersonaName: a.personaName,
|
||||
PersonaKnobs: a.personaKnobs,
|
||||
PersonaAwakening: a.awakeningFor,
|
||||
Timezone: a.cfg.Timezone,
|
||||
MaxRounds: defaultMaxRounds,
|
||||
Agent: defaultAgent,
|
||||
Agents: agents,
|
||||
Tools: a.dispatcher,
|
||||
Capacity: capDecider,
|
||||
OnCapacity: a.onCapacity,
|
||||
OnAudit: a.onToolAudit,
|
||||
OnTurnEnd: a.onTurnEnd,
|
||||
Memory: store,
|
||||
Retriever: a.retriever,
|
||||
Extractor: a.buildMemoryExtractor(),
|
||||
Checkpoint: checkpoint,
|
||||
Tracer: tracer,
|
||||
Flow: flowPub,
|
||||
Guards: guards,
|
||||
PersonaID: personaID,
|
||||
PersonaName: a.personaName,
|
||||
PersonaKnobs: a.personaKnobs,
|
||||
PersonaAwakening: a.awakeningFor,
|
||||
// 主人身份说明书按**会话**注入(design/11 §0 红线):只有主人车道的
|
||||
// 上下文里有它,群聊 / 陌生人私聊的返回空串 —— 那段知识绝不进它们的
|
||||
// 上下文,也绝不随之发给模型供应商。开关与判定见 persona_identity.go。
|
||||
PersonaKnowledgeFor: a.personaKnowledgeFor(envPath),
|
||||
Timezone: a.cfg.Timezone,
|
||||
MaxRounds: defaultMaxRounds,
|
||||
// 上下文溢出压缩:预算取自 CONTEXT_MAX_TOKENS(非正 = 关闭,
|
||||
// 与接线前一致),默认启用(见 wire_context.go)。Compactor 不注入,
|
||||
// 由 loop 选用内置的结构化 compactor(离线、不调模型)。
|
||||
MaxContextTokens: a.contextBudget(),
|
||||
WorkingMemory: memory.NewWorkingMemory(0),
|
||||
OnStream: a.streamChunk,
|
||||
Vision: visionResolver,
|
||||
@@ -429,11 +438,13 @@ func (a *app) defaultPersonaID() string {
|
||||
|
||||
// defaultInstructions returns the default persona's system prompt followed by the
|
||||
// personality/values/speechStyle/catchphrase/background sections (design/01
|
||||
// §2.2), falling back to its role text or a minimal instruction when neither is
|
||||
// set.
|
||||
// §2.2), falling back to its role text or a minimal instruction when neither is set.
|
||||
//
|
||||
// 主人身份说明书**不在这里**(P0-10 收窄后按会话注入,见 personaKnowledgeFor):
|
||||
// 静态拼进指令会让它进入该角色的每一个会话,含群聊与陌生人私聊。
|
||||
func (a *app) defaultInstructions() string {
|
||||
if p, ok := a.defaultPersona(); ok {
|
||||
return instructionsFromPersona(p)
|
||||
return a.personaInstructions(p)
|
||||
}
|
||||
return fallbackInstruction
|
||||
}
|
||||
Reference in new issue
Block a user