Files
nanoclaw/docs/zh/db-central.md
2026-05-12 13:14:17 +00:00

14 KiB
Raw Permalink Blame History

NanoClaw — 中央数据库模式Central DB Schema

data/v2.db 的完整参考,这是主机拥有的管理平面数据库。先阅读 db.md 了解三数据库概览、结构和跨挂载规则。

访问层:src/db/。权威模式参考:src/db/schema.ts(仅注释——实际创建通过 src/db/migrations/ 中的迁移运行)。


1. 表

1.1 agent_groups

代理工作区workspace。每个 1:1 映射到一个 groups/<folder>/ 目录,该目录包含 CLAUDE.md 和技能。容器配置位于 container_configs 中(见下方 §1.x在生成容器时会物化materialize一个 container.json 文件供容器运行器读取。

CREATE TABLE agent_groups (
  id               TEXT PRIMARY KEY,
  name             TEXT NOT NULL,
  folder           TEXT NOT NULL UNIQUE,
  agent_provider   TEXT,
  created_at       TEXT NOT NULL
);
  • 读取者:src/session-manager.tssrc/delivery.tssrc/router.ts
  • 写入者:src/db/agent-groups.ts

1.2 messaging_groups

每个平台聊天一行(一个 WhatsApp 群组、一个 Slack 频道、一个 1:1 私信等)。

CREATE TABLE messaging_groups (
  id                    TEXT PRIMARY KEY,
  channel_type          TEXT NOT NULL,
  platform_id           TEXT NOT NULL,
  name                  TEXT,
  is_group              INTEGER DEFAULT 0,
  unknown_sender_policy TEXT NOT NULL DEFAULT 'strict',
  created_at            TEXT NOT NULL,
  UNIQUE(channel_type, platform_id)
);
  • unknown_sender_policystrict(丢弃)、request_approval(请求管理员)、public(允许)。
  • 读取者:src/router.tssrc/delivery.tssrc/session-manager.ts
  • 写入者:src/db/messaging-groups.ts、频道设置流程

1.3 messaging_group_agents

接线表wiring哪个代理组处理哪个消息组。多对多——同一频道可以路由到多个代理参见 isolation-model.md)。

CREATE TABLE messaging_group_agents (
  id                 TEXT PRIMARY KEY,
  messaging_group_id TEXT NOT NULL REFERENCES messaging_groups(id),
  agent_group_id     TEXT NOT NULL REFERENCES agent_groups(id),
  trigger_rules      TEXT,
  response_scope     TEXT DEFAULT 'all',
  session_mode       TEXT DEFAULT 'shared',
  priority           INTEGER DEFAULT 0,
  created_at         TEXT NOT NULL,
  UNIQUE(messaging_group_id, agent_group_id)
);
  • session_modeshared(每频道一个会话)、per-thread(每线程一个)、agent-shared(每个代理组跨所有频道一个)。
  • trigger_rulesJSON例如原生频道的正则表达式。
  • **副作用:**创建接线时也必须填充 agent_destinations——修改其中一个时不要忘记另一个(参见 §1.10)。

1.4 users

平台用户身份。ID 命名空间化:tg:123456discord:abcphone:+1555...email:a@x.com。一个人可能拥有多行——尚无跨频道关联。

CREATE TABLE users (
  id           TEXT PRIMARY KEY,
  kind         TEXT NOT NULL,
  display_name TEXT,
  created_at   TEXT NOT NULL
);
  • 写入者/读取者:src/db/users.ts;频道认证流程

1.5 user_roles

权限表。权限是用户级别的,永远不是代理组级别的。

CREATE TABLE user_roles (
  user_id        TEXT NOT NULL REFERENCES users(id),
  role           TEXT NOT NULL,
  agent_group_id TEXT REFERENCES agent_groups(id),
  granted_by     TEXT REFERENCES users(id),
  granted_at     TEXT NOT NULL,
  PRIMARY KEY (user_id, role, agent_group_id)
);
CREATE INDEX idx_user_roles_scope ON user_roles(agent_group_id, role);

不变量Invariants

  • role = 'owner' → 必须是全局的 (agent_group_id IS NULL)。在 grantRole() 中强制执行。
  • role = 'admin' → 全局NULL或限定到一个代理组。
  • 代理组 A 的 admin 隐含了 A 的成员身份——不需要 agent_group_members 行。

访问层:src/db/user-roles.tssrc/access.ts

1.6 agent_group_members

非特权用户的显式成员身份。Owner 和 admin 不需要此处的行——他们是隐式成员。

CREATE TABLE agent_group_members (
  user_id        TEXT NOT NULL REFERENCES users(id),
  agent_group_id TEXT NOT NULL REFERENCES agent_groups(id),
  added_by       TEXT REFERENCES users(id),
  added_at       TEXT NOT NULL,
  PRIMARY KEY (user_id, agent_group_id)
);

1.7 user_dms

私信DM频道发现的缓存。让主机无需每次都调用平台的 openConversation API 即可发送冷私信(批准卡片、配对码等)。

CREATE TABLE user_dms (
  user_id            TEXT NOT NULL REFERENCES users(id),
  channel_type       TEXT NOT NULL,
  messaging_group_id TEXT NOT NULL REFERENCES messaging_groups(id),
  resolved_at        TEXT NOT NULL,
  PRIMARY KEY (user_id, channel_type)
);

src/user-dm.ts 中的 ensureUserDm() 延迟填充。

1.8 sessions

会话注册表session registry。每个受 session_mode 约束的(代理组、消息组、线程)元组一行。仅存储生命周期元数据——不含消息。

CREATE TABLE sessions (
  id                 TEXT PRIMARY KEY,
  agent_group_id     TEXT NOT NULL REFERENCES agent_groups(id),
  messaging_group_id TEXT REFERENCES messaging_groups(id),
  thread_id          TEXT,
  agent_provider     TEXT,
  status             TEXT DEFAULT 'active',
  container_status   TEXT DEFAULT 'stopped',
  last_active        TEXT,
  created_at         TEXT NOT NULL
);
CREATE INDEX idx_sessions_agent_group ON sessions(agent_group_id);
CREATE INDEX idx_sessions_lookup     ON sessions(messaging_group_id, thread_id);
  • resolveSession() 解析:src/session-manager.ts
  • 创建会话还会通过 initSessionFolder() 配置会话文件夹和两个会话数据库——参见 db-session.md

1.9 pending_questions

ask_user_question MCP 工具将一个交互式问题停放在此处,容器通过 questionId 将传入的 system 消息匹配回来。

CREATE TABLE pending_questions (
  question_id    TEXT PRIMARY KEY,
  session_id     TEXT NOT NULL REFERENCES sessions(id),
  message_out_id TEXT NOT NULL,
  platform_id    TEXT,
  channel_type   TEXT,
  thread_id      TEXT,
  title          TEXT NOT NULL,
  options_json   TEXT NOT NULL,
  created_at     TEXT NOT NULL
);

1.10 agent_destinations

用于出站发送的权限 ACL 和名称解析映射。代理请求 send_message(to="dev-channel") 必须在此有一个 local_name = 'dev-channel' 的行,否则发送将被拒绝为 unknown destination

CREATE TABLE agent_destinations (
  agent_group_id TEXT NOT NULL REFERENCES agent_groups(id),
  local_name     TEXT NOT NULL,
  target_type    TEXT NOT NULL,   -- 'channel' | 'agent'
  target_id      TEXT NOT NULL,   -- messaging_group_id | agent_group_id
  created_at     TEXT NOT NULL,
  PRIMARY KEY (agent_group_id, local_name)
);
CREATE INDEX idx_agent_dest_target ON agent_destinations(target_type, target_id);

**投影不变量(负载关键)。**中央表是真实数据源,但每个运行中的容器从其自己的 inbound.db 读取投影(参见 db-session.md §2.3)。任何在容器运行时修改 agent_destinations 的代码还必须调用 writeDestinations()src/session-manager.ts),否则容器将因过时数据拒绝发送。已知调用点:createMessagingGroupAgent()src/db/messaging-groups.ts 中,create_agent 系统动作在 src/delivery.ts 中。

访问层:src/db/agent-destinations.ts

1.11 pending_approvals

两个工作流共享此表:

  • 会话绑定的 MCP 批准——install_packagesadd_mcp_serversession_id 有值。
  • OneCLI 凭证批准——session_id 可为 NULLagent_group_id + channel_type + platform_id 路由管理卡片。
CREATE TABLE pending_approvals (
  approval_id         TEXT PRIMARY KEY,
  session_id          TEXT REFERENCES sessions(id),
  request_id          TEXT NOT NULL,
  action              TEXT NOT NULL,
  payload             TEXT NOT NULL,
  created_at          TEXT NOT NULL,
  agent_group_id      TEXT REFERENCES agent_groups(id),
  channel_type        TEXT,
  platform_id         TEXT,
  platform_message_id TEXT,
  expires_at          TEXT,
  status              TEXT NOT NULL DEFAULT 'pending',
  title               TEXT NOT NULL DEFAULT '',
  options_json        TEXT NOT NULL DEFAULT '[]'
);
CREATE INDEX idx_pending_approvals_action_status ON pending_approvals(action, status);
  • statuspending | approved | rejected | expired
  • platform_message_id 让主机在决策后原地编辑管理卡片。
  • 访问层:src/db/sessions.ts;清理和递送:src/onecli-approvals.ts

1.12 unregistered_senders

审计追踪:每次消息被丢弃(未知发送者、严格策略),我们在此递增计数器,以便管理员可以看到谁一直在尝试联系。

CREATE TABLE unregistered_senders (
  channel_type       TEXT NOT NULL,
  platform_id        TEXT NOT NULL,
  user_id            TEXT,
  sender_name        TEXT,
  reason             TEXT NOT NULL,
  messaging_group_id TEXT,
  agent_group_id     TEXT,
  message_count      INTEGER NOT NULL DEFAULT 1,
  first_seen         TEXT NOT NULL,
  last_seen          TEXT NOT NULL,
  PRIMARY KEY (channel_type, platform_id)
);
CREATE INDEX idx_unregistered_senders_last_seen ON unregistered_senders(last_seen);

写入者:recordDroppedMessage()src/db/dropped-messages.ts 中。冲突时递增 message_count + last_seen

1.13 Chat SDK 桥接表

支持 Chat SDK 桥接使用的 SqliteStateAdapter 的状态(参见 api-details.md。NanoClaw 代码很少直接接触这些表——它们由 src/state-sqlite.ts 拥有。

CREATE TABLE chat_sdk_kv (
  key        TEXT PRIMARY KEY,
  value      TEXT NOT NULL,
  expires_at INTEGER                    -- unix 时间戳,可为空
);

CREATE TABLE chat_sdk_subscriptions (
  thread_id     TEXT PRIMARY KEY,
  subscribed_at TEXT NOT NULL DEFAULT (datetime('now'))
);

CREATE TABLE chat_sdk_locks (
  thread_id  TEXT PRIMARY KEY,
  token      TEXT NOT NULL,
  expires_at INTEGER NOT NULL
);

CREATE TABLE chat_sdk_lists (
  key        TEXT NOT NULL,
  idx        INTEGER NOT NULL,
  value      TEXT NOT NULL,
  expires_at INTEGER,
  PRIMARY KEY (key, idx)
);

1.14 schema_version

迁移账本migration ledger由迁移运行器§2写入。

CREATE TABLE schema_version (
  version INTEGER PRIMARY KEY,
  name    TEXT NOT NULL,
  applied TEXT NOT NULL
);

1.15 container_configs

每个代理组的容器运行时配置。providermodelpackages、MCP 服务器、挂载、CLI 范围等的真实数据源。在生成容器时物化到 groups/<folder>/container.json

CREATE TABLE container_configs (
  agent_group_id         TEXT PRIMARY KEY REFERENCES agent_groups(id) ON DELETE CASCADE,
  provider               TEXT,
  model                  TEXT,
  effort                 TEXT,
  image_tag              TEXT,
  assistant_name         TEXT,
  max_messages_per_prompt INTEGER,
  skills                 TEXT NOT NULL DEFAULT '"all"',
  mcp_servers            TEXT NOT NULL DEFAULT '{}',
  packages_apt           TEXT NOT NULL DEFAULT '[]',
  packages_npm           TEXT NOT NULL DEFAULT '[]',
  additional_mounts      TEXT NOT NULL DEFAULT '[]',
  cli_scope              TEXT NOT NULL DEFAULT 'group',   -- disabled | group | global
  updated_at             TEXT NOT NULL
);
  • 读取者:src/container-config.tssrc/container-runner.tssrc/cli/dispatch.ts(范围强制执行)、src/claude-md-compose.ts
  • 写入者:src/db/container-configs.tssrc/modules/self-mod/apply.tssrc/backfill-container-configs.ts

2. 迁移系统

迁移migrations位于 src/db/migrations/,每个迁移一个文件。运行器:runMigrations()src/db/migrations/index.ts 中。它:

  1. 如果不存在则创建 schema_version
  2. 读取 MAX(version)——称为 current
  3. 对每个 version > current 的迁移,在事务内执行 up(db) 并追加 schema_version 行。
# 文件 引入内容
001 001-initial.ts 核心表:agent_groupsmessaging_groupsmessaging_group_agentsusersuser_rolesagent_group_membersuser_dmssessionspending_questions
002 002-chat-sdk-state.ts chat_sdk_kvchat_sdk_subscriptionschat_sdk_lockschat_sdk_lists
003 003-pending-approvals.ts pending_approvals(会话绑定 + OneCLI 字段)
004 004-agent-destinations.ts agent_destinations + 从现有 messaging_group_agents 接线回填
007 007-pending-approvals-title-options.ts ALTER TABLE pending_approvals 添加 titleoptions_json(改造在 003 和 007 之间创建的数据库)
008 008-dropped-messages.ts unregistered_senders
009 009-drop-pending-credentials.ts 删除已废弃的 pending_credentials
014 014-container-configs.ts container_configs——每个代理组的容器运行时配置
015 015-cli-scope.ts ALTER TABLE container_configs ADD COLUMN cli_scope

编号 005 和 006 有意空缺——迁移在早期开发期间重新编号。

会话数据库模式(INBOUND_SCHEMAOUTBOUND_SCHEMA在此处进行版本管理。它们使用 CREATE TABLE IF NOT EXISTS,因此当重新打开旧版本构建的会话文件时,新列通过会话数据库的延迟迁移辅助函数(migrateDeliveredTable() 等)添加。参见 db-session.md