Skip to content

refactor(agent): 轮次不再携带短期 JWT,恢复时按发起账号重新授权 - #1726

Draft
chen-ran wants to merge 1 commit into
refactor/context-prepfrom
refactor/turn-actor-identity
Draft

chen-ran wants to merge 1 commit into
refactor/context-prepfrom
refactor/turn-actor-identity

Conversation

@chen-ran

@chen-ran chen-ran commented Nov 2, 2026

Copy link
Copy Markdown
Member

Author

  • Human
  • Agent

Type

  • bug
  • feat
  • test

Summary

叠在 #1724 之上(base 为 refactor/context-prep)。#1724 合并后改为对 main。

问题

Channel → Server 的轮次、定时任务和 Web 轮次原来都会签发一枚短期 JWT(5–10 分钟),随命令传给 Server。这套令牌是 agent 还是独立 TypeScript 进程时用来回调 Server 的(2026-02 引入);agent 并入 Go 进程(#264)之后,运行中已经没有地方用它鉴权:工具调用只把它当元数据,外部 runtime 回调工具靠的是不可猜的路由 key。唯一还校验它的是入轮时的 recordRunResumeContext(#1391),它从令牌里取出身份 claims 存给停机恢复用。签发和使用之间等太久,令牌就过期:

  • Discuss 排队、历史加载、重组之后入轮,报 invalid session credential for resume(Memoh-Cloud feat(web): open localhost links from markdown/terminal in the browser tab #685)。
  • follow-up 队列把整条命令连令牌原文写进数据库,排队超过 5 分钟的消息一开始就失败。
  • 运行超过 5 分钟后才派生的子 agent,记录恢复上下文时用的是父 run 的令牌,同样失败。

改动

  • turn.StartTurnCommand / ChatRequest / RunConfigRequest 去掉 Token、ChatToken、SessionToken,改带 ActorAccountID:这一轮以哪个账号的权限运行。
    • Channel 按原来令牌的主体计算:bot 所有者;外部 runtime 会话取 runtime 所有者。
    • Web 用登录用户(runtime 会话取 runtime 所有者),定时任务用所有者,审批 / ask_user / 重试 / 编辑用响应人。
    • 内部 RPC 本身已认证,这个字段与命令里的 BotID、UserID 同等可信。
  • 恢复上下文记录 ActorAccountID;恢复前照旧重新校验账号可用、对 bot 仍有聊天权限。旧版本写下的 TokenClaims / ChatClaims 仍可读取。恢复不再依赖 JWT 密钥。
  • 运行身份里的 SessionToken 改为 ActorAccountID,子 agent 继承它记录恢复上下文;工具会话上下文、外部 runtime 输入里只作元数据的 SessionToken 删除。
  • 删除只剩它自己引用的 chat_route 令牌:
    • JWT 中间件里对它跳过账号会话校验的分支(它在所有受 JWT 保护的接口上都生效);
    • 仓库内外都没有调用方的 POST /bots/{id}/channel/{platform}/send_chat;
    • Channel、Web、定时任务里签发令牌的代码。
    • 重新生成 OpenAPI 与 SDK。
  • 本 PR 取代了 refactor(agent): 收紧上下文准备,每轮只读一次历史,历史窗口只留一条查询 #1724 里"Discuss 在派发时签发凭据"那一项(DiscussSessionConfig.Credentials 改为 ActorAccountID)。

兼容性

  • split 部署两侧可以任意顺序升级:新 Server 忽略旧 Channel 命令里的令牌字段;旧 Server 收到不带令牌的命令时,恢复上下文没有 claims,恢复照旧进行。
  • 停机前写下的恢复上下文仍按旧 claims 授权。
  • send_chat 接口删除是对外 API 的破坏性变更;仓库内(Web、桌面端、SDK 使用方)和 Cloud 仓库都没有找到调用方。
  • Cloud 仓库在 packages/memoh 之外没有使用这些令牌;同步到 Cloud 时仍需核对 fork 侧有无改动。

Related Issues

Refs felinics/Memoh-Cloud#685

Validation

  • go test ./internal/... ./cmd/... 全部通过。
  • 本地 PostgreSQL 18(按本分支迁移建库)上跑 TestPostgres*:internal/agent/application(含停机恢复、决策续跑、历史重置后恢复)、cmd/agent(含 Discuss、定时任务端到端)、internal/chat/...、internal/schedule 通过。
  • 新增 / 改写的测试:
    • 恢复上下文只记录发起账号和截止时间,不落任何凭据。
    • 恢复时重新授权:外部会话 scope 不符视为不可恢复;没有可用的账号校验就拒绝;旧 claims 能还原发起账号。
    • Channel 的发起账号:模型会话取 bot 所有者,ACP 会话取 runtime 所有者。
    • 审批接口的操作人取自普通用户 JWT(原来用 chat_route 令牌调用,只因中间件跳过校验才能通过)。
  • golangci-lint 对改动的包没有新增告警。

Screenshots / Recordings

尚未完成。开发环境与真实 UI 验证还没做,需要验证:Web 聊天、Telegram(fake Bot API)chat 与 Discuss、Discuss 排队超过 5 分钟后入轮、停机恢复。验证完成前保持 draft。

Human QA

  • Human QA passed

🤖 Generated with Claude Code

Channel → Server 的轮次、定时任务和 Web 轮次原来都签发一枚短期 JWT(5–10 分钟)
随命令传给 Server。这套令牌是 agent 还是独立进程时用来回调 Server 的;agent
并入进程后,运行中已没有地方用它鉴权,只剩入轮时 recordRunResumeContext 校验
它、从中取出身份 claims 给停机恢复用。签发和使用之间一旦等太久就过期,于是:

- Discuss 排队、历史加载、重组后入轮报 "invalid session credential for resume"
  (Memoh-Cloud #685);
- follow-up 队列把整条命令连令牌原文写进数据库,排队超过 5 分钟的消息开始即失败;
- 运行 5 分钟后再派生的子 agent,记录恢复上下文时用的是父 run 的令牌,同样失败。

改为:

- turn.StartTurnCommand / ChatRequest / RunConfigRequest 去掉 Token、ChatToken、
  SessionToken,改带 ActorAccountID:run 以哪个账号的权限运行。Channel 照原来
  令牌的主体计算(bot 所有者,外部 runtime 会话取 runtime 所有者),Web 用登录
  用户,定时任务用所有者,审批 / ask_user / 重试 / 编辑用响应人。内部 RPC 本身
  已经认证,这个字段与 BotID、UserID 同等可信。
- 恢复上下文记录 ActorAccountID,恢复前照旧重新校验账号可用、对 bot 仍有聊天
  权限;旧版本写下的 TokenClaims / ChatClaims 仍可读取。恢复不再依赖 JWT 密钥。
- 运行身份里的 SessionToken 改为 ActorAccountID,子 agent 继承它记录恢复上下文;
  工具会话上下文、外部 runtime 输入里只作元数据的 SessionToken 删除。
- 删除只剩它自己引用的 chat_route 令牌:JWT 中间件对它跳过账号会话校验的分支、
  无人调用的 POST /bots/{id}/channel/{platform}/send_chat,以及 Channel、Web、
  定时任务里签发令牌的代码。重新生成 OpenAPI 与 SDK。

Refs felinics/Memoh-Cloud#685

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added bug Fixes a bug or unexpected behavior change:server Changes backend code, configuration, or API contracts change:web Changes web frontend or shared frontend packages size:M PR size uses the larger of added or deleted lines, excluding generated files labels Nov 2, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Fixes a bug or unexpected behavior change:server Changes backend code, configuration, or API contracts change:web Changes web frontend or shared frontend packages size:M PR size uses the larger of added or deleted lines, excluding generated files

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant