Skip to content

[人格] default 卡无条件进所有没建卡的身份;面板「注入生效文本」是前端另拼的一份 #497

Closed

Description

@modusensus

两件事,同一页

接手 persona 这条线时对着 main 实测出来的两个缺陷。都不是「功能没做」,是做出来的那半与宣称的语义不一致。

一、default 人格卡会无条件进所有没建卡的身份(包括宿主里跑的外部 bot)

src/user-settings.js 之前的寻址(原住在 src/settings.js 的 getPersonaFor)是:

  • 身份命中 byAgent 卡且卡开着 → 用这张卡;
  • 身份没有卡、或有卡但卡被关掉 → 一律落 default 卡。

第二条让两件事失效:

  1. default 卡开着时,宿主里任何自带身份与设定的 bot(DS Bot 那类)每一帧都会收到一份「你的人格名字:…」,与它自己的身份声明撞在同一轮里。而 agent_scope 是用户可给的参数,不是可信边界,挡不住。
  2. 「把这张卡关掉」在界面上有开关、实际不生效——关掉的卡仍然通过 default 拿到一份人格。

面板上那句 未启用——这个身份的会话将使用默认卡 说明这不是不知道的行为,是当时定的口径;问题是这个口径把「解析不到身份」与「有身份但没配置」当成同一件事。

二、面板「Agent 眼中的你(注入生效文本)」不是生效文本

lib/client.js 里那段是前端自己拼的:只有 profile 与 rules 两条列表,没有 [用户设置] 表头、没有 - 用户画像: 前缀、完全没有人格三行(注释自己写着「纯前端拼接…零后端新请求」)。而真正的渲染在注入器里,两处各写各的,标题却声称是同一件事的读数——这类「两张皮」在本仓是被反复钉过的(#411 的回收口径、#179 的注入预览)。

后果很具体:用户开着人格卡,看预览说「没有人格」,就会去怀疑注入没生效;反过来预览里也不会暴露转义后的真实形状。

修法(一条 PR)

  1. 渲染整体搬到 src/user-settings.js:escapePromptVars / resolvePersonaCard / renderUserSettingsBlock,注入器与预览调同一份;src/inject.js 的 renderUserSettings 只剩一行委托,同名转义闭包改为委托(其余调用点不动)。
  2. 新增 opt-in 键 personaStrictAddressing(默认 false = 历史行为逐字节不变):打开后「身份没有卡」与「卡被显式关掉」都不注入人格,default 退回它的本意——只兜解析不到会话身份的无名会话。settings.js 白名单成对注册,不进 LIGHT_MODE_OFF(纯判定分支)。
  3. GET /api/dsh-mneme/persona 增 preview 字段(text / source / agent / configGate),支持 ?agent=<身份> 逐张卡预览;面板只显示后端给的文本,读失败时 fail-closed 显示「未知」,绝不回退到前端拼的版本。
  4. 删掉 settings.getPersonaFor(改完后生产代码零调用点),寻址只留一处;原锁它的两条用例改指 resolvePersonaCard,并补一条 strict 用例。

明确不在这里做

  • 画像/规则没有独立开关:它们比 persona 早,personaEnabled 只管人格行。给它们加闸是行为变更,影响所有用户,另议。
  • 「从记忆里提取画像/人格」:本条提出时确实不存在(无路由、无按钮、无 LLM 调用点),所以列在了「不做」里;维护者随后指定要做,已作为 PR fix(persona)+feat(profile): 收回 default 卡兜底、生效文本单源渲染,并新增画像提取草稿(#497) #498 的第三段落地:新键 profileExtractEnabled|默认关 + POST /api/dsh-mneme/profile/extract。形态上有两条硬边界:只出草稿(模块连 settings 都不注入,采用是面板上另一次显式 PUT),以及空库与解析失败都报错、绝不回一张空草稿冒充「这次没提炼出东西」。
  • 人格卡单选互斥:运行时每轮本来只会用一张卡;把存储层做成互斥会牺牲 v1.2 多卡(不同 agent 用不同卡)的意义,等 strict 口径上线后看是否还需要。

验证口径

回归锁:test/persona-addressing.test.js(strict 四例 + 一条现状锁)、test/user-settings-preview.test.js(预览与注入器逐字节同源 + 寻址读数 + 总闸关闭如实说)、test/persona-settings.test.js(寻址唯一实现)、test/client.test.js(预览必须由后端给、前端拼接形态不许回来、双语齐全)。变异自证两条:摘掉 strict 分支 → 4 条红;预览忽略 agent 参数 → 3 条红(含逐字节同源那条)。

Activity

  1. added
    bug功能异常、崩溃、数据错误(agent 诊断 → 人工确认)
    on Oct 21, 2026
  2. moved this from 📋 Backlog to 🔨 In Progress in dsh-mneme 任务看板on Oct 21, 2026
  3. modusensus commented on Oct 21, 2026

    @modusensus
    MemberAuthor

    PR #498 落地了本条描述的两处修补(严格寻址 + 预览同源)。有一条已知边界留在这里,不藏在代码注释里:

    严格寻址的判据是会话身份标签(session.header.agentPreset)。如果一个外部 bot 与用户自己的会话共用同一个 preset 标签,那么这一格只能做到「没建卡的身份不注入」;而一旦为该标签建了卡(用户想让日常会话有人格),同一标签下的 bot 会话也会一起拿到那张卡。

    要把这两者分开,需要的是按 workspace 维度的注入排除,它会把政策轴的语义牵进来——而 #471 的 scopeState 目前只管记忆行的可见性,不管 user_settings(画像/规则/人格)。那是另一个议题,不在 #498 里顺手做。

    另外两点与「人格为什么看着没起作用」有关,属于使用面而不是缺陷:

    • 画像与规则不受 personaEnabled 管辖。如果画像正文里写了身份句(例如「你是某某」),它在每个会话每一帧都注入,与人格卡的开关、与严格寻址都无关;要按身份分持人格,这类句子应该待在卡片字段里。
    • minimal 预设的会话由宿主整体压制注入(runtime contexts (ctx.systemPrompt.context) never reach the model — dsh 0.1.5-rc.1 #175 的定论,面板状态页有提示),那种会话里人格、画像、记忆都不会出现,与寻址口径无关。
  4. moved this from 🔨 In Progress to ✅ Done in dsh-mneme 任务看板on Oct 21, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bug功能异常、崩溃、数据错误(agent 诊断 → 人工确认)

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions