Built-ins

auth Plugin

详细说明 auth 内建 plugin 的职责、授权链路、角色解析方式、可调用动作,以及它和 guard、effect、resolve 的关系

auth Plugin

auth 是当前 Downcity 内建 plugin 里最“平台规则化”的一个。

它不是为了给 agent 增加某个业务功能,而是为了回答三个基础问题:

  • 谁可以进入 chat 链路
  • 平台已经观察到了哪些用户和 chat
  • 某个用户当前的有效角色是什么

它到底做什么

auth 主要负责四件事:

  1. 在 chat 入站时做授权判断
  2. 记录观察到的用户和会话主体
  3. 解析用户在某个渠道中的角色
  4. 通过 action 暴露授权配置和快照读写能力

所以它横跨了:

  • 入口守卫
  • 运行观察
  • 权限解析
  • 控制面动作

为什么它是“特殊 plugin”

和其他大多数内建 plugin 不一样,auth 不是普通的可选插件。

它当前的可用性语义是:

  • enabled: true
  • available: true

也就是说,它始终被视为可用,不走常规的开关型生命周期。

这很合理,因为一旦把授权逻辑也做成“可随时完全失效的可选能力”,整个平台规则层就会变得不稳定。

它使用了哪些 plugin 能力

auth 用到的能力面是:

  • availability
  • hooks.guard
  • hooks.effect
  • resolves
  • actions

它没有使用:

  • setup
  • usage
  • system
  • http.runtime

这说明 auth 不是一个需要 UI 安装向导的插件,也不是一个主要靠 system prompt 提示词起作用的插件。

典型运行流

一个典型的 chat 消息进入系统时,auth 大致会按这个顺序参与:

  1. chat 入站流程触发授权检查点
  2. authguard 钩子根据渠道、chatId、userId 等信息判断是否放行
  3. 如果不放行,链路直接报错并停止
  4. 如果放行,系统继续处理消息
  5. 后续的主体观察点会调用 effect,把用户 / chat 信息记入观察态
  6. 当下游需要知道“这个用户是什么角色”时,会调用 resolve

换句话说:

  • guard 决定能不能进
  • effect 负责留下观察记录
  • resolve 提供角色答案

典型场景

场景一:只允许特定 Telegram 用户给 agent 发消息

你可以把授权配置写入 auth,然后所有 Telegram 入站消息都会先经过 guard

如果用户不在允许名单里,消息不会进入后续 agent 执行阶段。

场景二:第一次接入某个群聊后,想知道系统已经观察到了哪些主体

这时可以通过 snapshot action 读取当前快照,查看:

  • 已记录的用户
  • 已记录的 chats
  • 当前生效的授权配置

场景三:下游能力要根据用户角色决定是否放行

例如:

  • 管理员可以使用高风险工具
  • 普通成员只能执行只读任务

这时下游可以调用角色解析点,而不需要自己重复读授权存储。

在 SDK 里怎么挂载

import { Agent } from "@downcity/agent";
import { ChatAuthorizationPlugin } from "@downcity/plugins";

const agent = new Agent({
  id: "chat-agent",
  path: "/path/to/project",
  tools: {},
  plugins: [new ChatAuthorizationPlugin()],
});

chat-authorization 本身更常被运行时自动消费,而不是像普通业务插件那样由你手动频繁调用。

可调用动作

chat-authorization 暴露了四个最核心的动作。

Action作用适合什么时候用
snapshot读取授权快照想查看当前观测态和配置
readConfig读取授权配置想做控制面展示或调试
writeConfig写入授权配置想批量更新授权规则
setUserRole设置用户角色想单独修改某个用户的角色

读取当前授权快照

const snapshot = await agent.plugins.runAction({
  plugin: "auth",
  action: "snapshot",
});

这个结果通常会包含:

  • 当前授权配置
  • 已记录用户
  • 已记录 chats

读取当前授权配置

const config = await agent.plugins.runAction({
  plugin: "auth",
  action: "readConfig",
});

写入新的授权配置

const result = await agent.plugins.runAction({
  plugin: "auth",
  action: "writeConfig",
  payload: {
    config: {
      telegram: {
        enabled: true,
      },
    },
  },
});

为某个用户设置角色

const result = await agent.plugins.runAction({
  plugin: "auth",
  action: "setUserRole",
  payload: {
    channel: "telegram",
    userId: "123456",
    roleId: "admin",
  },
});

它和 Hook / Resolve 的关系

auth 是理解这些机制最典型的内建样本之一:

  • guard:阻止不该进入的消息
  • effect:记录观察到的主体
  • resolve:给出用户有效角色

如果你读完 auth 还对这些概念不够直观,建议继续看:

它和 runtime ownership 的边界

auth 不是一个长期持有连接或线程的 runtime owner。

它更像一层规则编排:

  • 在关键点上挂规则
  • 把底层授权配置与状态存储统一暴露出来
  • 让别的能力通过标准接口读取角色结果

如果你把它当作长期运行实例,会很容易误以为“权限判断应该塞进某个长期运行实例内部”。当前设计恰恰避免了这种耦合。

需要注意的边界

它只处理 chat 授权与角色解析相关问题

auth 不是一个通用 ACL 系统,也不是任意资源访问控制框架。

它当前聚焦在 chat 渠道场景。

它依赖标准的渠道信息

当前渠道识别依赖的是标准 channel 值,例如:

  • telegram
  • feishu
  • qq

如果传入了无效 channel,相关动作或 hook 会直接报错。

它不是 UI 配置型插件

你不会像 webasrtts 那样通过 setup / usage 去安装模型或切换 provider。

auth 的核心价值在规则判断,不在依赖安装。

什么时候优先参考它

当你要设计这些能力时,优先参考 auth

  • 入站守卫
  • 用户 / 会话主体观测
  • 角色解析
  • 平台级规则型插件

相关文档