Skip to main content

ChatEvent

chatevent 是 ChatArch 的协作事件观察包:提供类型化事件 envelope、SQLite 事件账本、平台 normalizer 和 Web Observatory,用于观察 Discourse、Zulip、Gitea、GitHub 等协作平台的真实动作。

当前 0.1.0 范围聚焦 Discourse、Zulip、Gitea、GitHub。每个平台都有明确 action catalog,订阅和 UI 不再把任意 tag 当成事件语义。

平台官方 webhook / event queue / API cursor -> ChatEvent -> SQLite -> Observatory / API

Gateway 路由和 Agent 执行不在当前包的阶段范围内。

英文版见 README.en.md

文档

  • MkDocs 源码:docs/
  • 本地构建:
uv sync --extra docs
uv run mkdocs build --strict
uv run mkdocs serve

ChatArch 包文档目标地址:

https://arch.gh.wzhecnu.cn/ChatEvent/

从源码安装

uv sync --extra serve --extra test --extra docs
uv run --extra serve chatevent --tree

0.1.0 是第一个完整 Event Hub 版本:包含 Observatory、SQLite 事件账本、平台 action registry、REST API/CLI 对应、订阅编辑和 ChatArch 内部默认路径。

CLI

chatevent
  --tree                         Print this command tree
  --version                      Print package version
  paths [--json]                 Show ChatArch-owned runtime paths
  serve [--host HOST] [--port PORT] [--db DB]
                                 Run the local Event Observatory
  schema event|subscription      Print JSON Schema contracts
  platforms [--json]             List supported platforms and action kinds
  record-json FILE [--db DB]     Validate and write one ChatEvent JSON file
  api health                     GET /api/health from a running Event Hub
  api stats                      GET /api/stats
  api platforms                  GET /api/platforms
  api schema event|subscription  GET /api/schema/{kind}
  api subscriptions [--enabled]  GET /api/subscriptions
  api subscription ID            GET /api/subscriptions/{id}
  api events [filters]           GET /api/events
  api event DEDUPE_KEY           GET /api/events/{dedupe_key}
  api record-json FILE           POST /api/events
  api save-subscription FILE     POST /api/subscriptions
  api delete-subscription ID     DELETE /api/subscriptions/{id}
  capture zulip-once [options]   Official Zulip event-queue capture pass

启动 Event Observatory

uv run --extra serve chatevent serve \
  --host 127.0.0.1 \
  --port 8765

打开:

http://127.0.0.1:8765/

当前服务器 demo 入口:

ChatArch 内部默认目录

ChatEvent 是 ChatArch 系列包,默认运行态必须留在 ChatArch home 内部。ChatArch home 的解析顺序是 CHATARCH_HOME,未设置时使用 ~/.chatarch

<chatarch-home>/
└── chatevent/
    ├── events.db              # SQLite 事件账本和订阅配置
    ├── events.db-wal          # SQLite WAL,运行时可能出现
    ├── events.db-shm          # SQLite shared-memory,运行时可能出现
    └── secrets/
        └── admin-token        # 可选 Web/REST 订阅写操作管理员 token

默认数据库解析顺序:

  1. CLI 显式 --db <path>
  2. CHATEVENT_DB=<path>
  3. $CHATARCH_HOME/chatevent/events.db
  4. ~/.chatarch/chatevent/events.db

首次使用默认路径时,如果发现旧版 ~/.chatevent/events.db 且新数据库不存在,ChatEvent 会把旧库复制到 ChatArch 内部路径;旧文件保留不删除。显式 --dbCHATEVENT_DB 不触发自动迁移。

可用下面的命令回读当前路径,不会输出 token 值:

uv run chatevent paths --json

SQLite 内部主要有两张表:

  • subscriptions:订阅配置和状态,body 保存完整 Subscription JSON;last_cursorlast_event_at 等更新也在这里。
  • events:规范化后的 ChatEventbody 保存完整事件 JSON,索引列保存 source、kind、subscription_id、captured_at 和 seen_count。

平台侧 webhook 注册、Zulip secret 文件、Nginx upstream、运行端口等不写入 SQLite;它们属于外部平台或运行时部署配置,凭据不写入项目文件。

刷新机制

Observatory 当前使用前端轮询,不是 WebSocket/SSE:

  • 页面打开后立即加载一次;
  • 5 秒 自动刷新;
  • 点击 刷新 / Refresh 会立即手动刷新;
  • 搜索输入约 260ms debounce 后刷新;
  • 来源、事件类型和时间范围筛选变化后立即刷新。

每次刷新会请求 /api/stats/api/subscriptions/api/events/api/platforms。事件流顶层只保留“来源”和“时间”两个下拉框;事件类型、订阅/渠道、关键词和自定义开始/结束时间在“高级选项”里组合筛选。事件类型 checkbox 会随来源联动,避免把不同平台 action 混在同一个下拉框里。

事件语义

产品语义使用这些字段表达:

  • source:平台来源,例如 zulipdiscoursegiteagithub
  • kind:平台动作,例如 message.createdpost.createdreply.createdissue.openedcommit.pushedpull_request.merged
  • conversation_id / subject_id / subject_type:动作发生在哪里、对象是什么。
  • capture_mode:捕获机制,不是业务动作。新接入使用 webhookevent_queueapi_cursorpollmanual_backfillgateway_forwardtest_fixturesynthetic;旧数据里的 push/pull 仅兼容读取。
  • tags:筛选或路由标签,不定义平台来源或动作。

动作 + 承载目标

ChatEvent 现在把订阅和事件都表达成“动作 + 承载目标”:

Subscription = source + actions/event_kinds + scope/target + capture_modes + filters
ChatEvent    = source + action/kind + actor/role + target + subject + payload
  • Subscription.target:兼容和快速展示用的 canonical string,例如 repo:ChatArch/ChatEventpull_request:ChatArch/ChatEvent#4stream:demo/topic:loop
  • Subscription.scope:结构化承载目标,包含开放字符串 typekeydisplayurlparentmetadata,不把平台类型写死。
  • Subscription.actions:结构化动作选择器,由 event_kinds 自动派生,也可以显式保存 kindobject_typeverb 和扩展 metadata。
  • ChatEvent.action:本次真实发生的动作,例如 pull_request.merged / reply.created
  • ChatEvent.actor / actor_role:发起人及其平台角色,例如 maintainer、member、bot、moderator;角色是开放字符串,可继续细分。
  • ChatEvent.target:本次动作作用到的具体对象,并通过 parent 串起承载链,例如 repo -> pull_request -> issue_commentzulip_stream -> zulip_topic -> message

示例:

{
  "source": "github",
  "target": "pull_request:ChatArch/ChatEvent#4",
  "scope": {
    "type": "pull_request",
    "key": "ChatArch/ChatEvent#4",
    "parent": {"type": "repo", "key": "ChatArch/ChatEvent"}
  },
  "event_kinds": ["pull_request.opened", "pull_request.merged", "issue.commented"],
  "capture_modes": ["webhook", "api_cursor"]
}

Observatory 的 Event Stream 增加了 Target 列;点开事件详情后会显示 ActionAction targetTarget chain。Platform actions 面板也会显示每个 action 通常挂载的 target types。

支持平台与常见动作

查看 canonical registry:

uv run chatevent platforms
uv run chatevent platforms --json
平台 首选捕获方式 常见 action kinds
Zulip event_queue, api_cursor message.created, message.updated, reaction.added, reaction.removed, mention.created, topic.updated
Discourse webhook, api_cursor topic.created, post.created, reply.created, post.edited, post.deleted, mention.created, reaction.added
Gitea webhook, api_cursor push, commit.pushed, issue.opened, issue.closed, issue.commented, pull_request.opened, pull_request.updated, pull_request.merged, release.published
GitHub webhook, api_cursor push, commit.pushed, issue.opened, issue.closed, issue.commented, pull_request.opened, pull_request.synchronize, pull_request.closed, pull_request.merged, workflow_run.requested, workflow_run.in_progress, workflow_run.completed, release.published

注册监控

  1. 先在 ChatEvent 保存订阅:
curl -k -X POST https://event.public.wzhecnu.cn/api/subscriptions \
  -H 'Content-Type: application/json' \
  -d '{
    "id": "discourse-practice",
    "source": "discourse",
    "target": "category:agent-runs",
    "event_kinds": ["topic.created", "post.created", "reply.created"],
    "capture_modes": ["webhook", "api_cursor"]
  }'
  1. 再把平台官方捕获面指向 ChatEvent:
Discourse: https://event.public.wzhecnu.cn/webhooks/discourse?subscription_id=discourse-practice
Gitea:     https://event.public.wzhecnu.cn/webhooks/gitea?subscription_id=gitea-practice
GitHub:    https://event.public.wzhecnu.cn/webhooks/github?subscription_id=github-chatevent
Zulip:     用 `chatevent capture zulip-once` 做官方 event queue bounded capture pass

详细步骤见 docs/monitoring.md

API 表面

  • GET /api/health
  • GET /api/schema/event
  • GET /api/schema/subscription
  • GET /api/platforms
  • POST /api/subscriptions
  • GET /api/subscriptions
  • DELETE /api/subscriptions/{id}
  • POST /api/events
  • GET /api/events,支持 sourcekindsubscription_idqsincedaysfromtolimit
  • GET /api/events/{dedupe_key}
  • GET /api/stats
  • POST /webhooks/zulip?subscription_id=...
  • POST /webhooks/discourse?subscription_id=...,读取 X-Discourse-Event
  • POST /webhooks/gitea?subscription_id=...
  • POST /webhooks/github?subscription_id=...,读取 X-GitHub-Event

Webhook endpoint 接收官方平台形状 payload,规范化为 ChatEvent,幂等写入 SQLite,并保留清洗后的 raw_payload 供 Observatory 调试。

CLI 与 REST API 对应

ChatEvent 可以当作一个轻量 Event Hub:平台官方 webhook / event queue / API cursor 负责把原始动作送进来,ChatEvent 负责规范化、去重、保存;下游系统通过 REST API 读取事件,CLI 的 api 命令组就是这些 REST endpoint 的命令行对应。

默认 base URL 是 CHATEVENT_API_URL,未设置时使用 http://127.0.0.1:8765;也可以对每个命令传 --base-url

CLI REST API 用途
chatevent api health GET /api/health 读服务健康状态和 DB 路径。
chatevent api stats GET /api/stats 读事件数、来源数、重复投递数。
chatevent api session GET /api/session 校验当前 API token 或登录 cookie 并返回用户/角色。
chatevent api users GET /api/users 管理员列出用户。
chatevent api create-user <username> --new-password-file pass.txt POST /api/users 管理员创建账号密码用户,不返回 token。
chatevent api create-token [user_id] POST /api/me/tokenPOST /api/users/{id}/token 为当前账号或指定用户生成一次性 arch_xxx API token。
chatevent api delete-user <id> DELETE /api/users/{id} 管理员删除用户。
chatevent api events --source discourse --days 7 GET /api/events?... 按 source/kind/subscription/q/since/days/from/to/limit 查询事件流。
chatevent api event <dedupe_key> GET /api/events/{dedupe_key} 直接读取某一条具体 event。
chatevent api record-json event.json POST /api/events 把已规范化的 ChatEvent JSON 写入 Event Hub。
chatevent api subscriptions GET /api/subscriptions 列出订阅。
chatevent api save-subscription subscription.json POST /api/subscriptions 通过 REST 保存订阅。
chatevent api delete-subscription <id> DELETE /api/subscriptions/{id} 删除订阅,不删除已捕获事件。

示例:

uv run chatevent api events \
  --base-url https://event.public.wzhecnu.cn \
  --source discourse \
  --days 7 \
  --limit 20

uv run chatevent api event \
  --base-url https://event.public.wzhecnu.cn \
  'discourse:post:35'

线上编辑与安全设定

Web Observatory 的 Subscriptions 标签页支持新建、编辑、启停和删除订阅;这些操作调用同一套 REST API。若配置了用户或 bootstrap 管理凭据,访问 / 会先进入账号密码登录页,登录后才显示 Observatory;事件流、统计、平台目录、schema、订阅等读取 API 也需要登录。网页端登录后可以直接编辑;CLI、模型或其他程序可以使用 X-ChatEvent-Admin-Token 携带账号的 arch_xxx API token,也可以通过 CLI 的账号密码参数先登录后操作。

CHATEVENT_ADMIN_TOKEN 仅是 bootstrap 管理员 API 凭据,不是 Web 登录方式;生产部署应配置 CHATEVENT_BOOTSTRAP_USERNAMECHATEVENT_BOOTSTRAP_PASSWORD_FILE 来初始化管理员账号密码。管理员登录后可以通过 POST /api/userschatevent api create-user <username> --new-password-file pass.txt 创建账号密码用户;用户登录后在“账号 / API Token”里主动生成自己的 arch_xxx token,服务端只保存 token hash。Subscription.owner_user_id 是数据隔离基础:member 创建/读取/删除订阅时只作用于自己的 owner;admin 可管理全部订阅。密码和 token 都不应写入源码、文档或 Git 历史。

mkdir -p ~/.chatarch/chatevent/secrets
chmod 700 ~/.chatarch/chatevent ~/.chatarch/chatevent/secrets
printf '<admin-token>\n' > ~/.chatarch/chatevent/secrets/admin-token
printf '<admin-password>\n' > ~/.chatarch/chatevent/secrets/admin-password
chmod 600 ~/.chatarch/chatevent/secrets/admin-token ~/.chatarch/chatevent/secrets/admin-password

CHATEVENT_BOOTSTRAP_USERNAME='admin@example.com' \
CHATEVENT_BOOTSTRAP_PASSWORD_FILE=~/.chatarch/chatevent/secrets/admin-password \
uv run --extra serve chatevent serve
uv run chatevent api create-token --username admin@example.com --password-file ~/.chatarch/chatevent/secrets/admin-password
uv run chatevent api save-subscription subscription.json --admin-token ...
uv run chatevent api delete-subscription discourse-practice --admin-token ...

删除订阅只删除 subscriptions 里的配置,不会删除 events 表中已经捕获的历史事件。

下游消费

Observatory 只是一个调试 consumer。其他系统可以按 checkpoint 轮询 Event Hub:

curl -k 'https://event.public.wzhecnu.cn/api/events?source=discourse&subscription_id=discourse-practice&since=2026-08-18T12:47:37Z&limit=50'

日期筛选示例:

curl -k 'https://event.public.wzhecnu.cn/api/events?days=7&source=discourse&limit=50'
curl -k 'https://event.public.wzhecnu.cn/api/events?from=2026-08-16T00:00:00Z&to=2026-08-18T00:00:00Z&limit=50'

其中 days 表示按服务器当前时间回看最近 N 天,from/to 表示按 captured_at 做日期区间筛选;since 仍保留给 consumer checkpoint,语义是严格返回 captured_at > since

返回体包含:

  • items:规范化 ChatEvent 列表;
  • count:本次命中的条数;
  • next_since:本批最新 captured_at。consumer 处理成功后保存它,下次作为 since 继续拉取。

推荐循环:

  1. consumer 保存自己的 last_since
  2. 请求 /api/events?since=<last_since>&source=...&kind=...&subscription_id=...
  3. 对每条 eventsource/kind/subject_id 做幂等处理。
  4. 全部处理成功后,把响应里的 next_since 存回 checkpoint。
  5. 如果 count=0,保持原 checkpoint,稍后再拉。

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

chatevent-0.1.5.tar.gz (72.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

chatevent-0.1.5-py3-none-any.whl (57.6 kB view details)

Uploaded Python 3

File details

Details for the file chatevent-0.1.5.tar.gz.

File metadata

  • Download URL: chatevent-0.1.5.tar.gz
  • Upload date:
  • Size: 72.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for chatevent-0.1.5.tar.gz
Algorithm Hash digest
SHA256 0617dc3d4ff7144f660d7645e050adf39b553938ff54352e10a60517abafc53b
MD5 9e378c7ccd85a47f96824e9e6ef4f428
BLAKE2b-256 9e5bed08801965a843b6ffdcd6fbe3f20eef00d123182c146c187bbad1aae390

See more details on using hashes here.

Provenance

The following attestation bundles were made for chatevent-0.1.5.tar.gz:

Publisher: publish.yml on ChatArch/ChatEvent

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file chatevent-0.1.5-py3-none-any.whl.

File metadata

  • Download URL: chatevent-0.1.5-py3-none-any.whl
  • Upload date:
  • Size: 57.6 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for chatevent-0.1.5-py3-none-any.whl
Algorithm Hash digest
SHA256 40c4cec6f716b1d71058bb07c448c5c8ff0cf2acf9babe79f9a9b235def20197
MD5 38b114eca22a482c1cc195cb34cee42c
BLAKE2b-256 3e09dc913eb7ab7d31591e5c4f7b7c122b9e610065b3a205ae6fb6f404e7559c

See more details on using hashes here.

Provenance

The following attestation bundles were made for chatevent-0.1.5-py3-none-any.whl:

Publisher: publish.yml on ChatArch/ChatEvent

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.2.2

2 files

0.2.1

2 files

0.2.0

2 files

This release

0.1.5 This release

2 files

0.1.4

2 files

0.1.3

2 files

0.1.2

2 files

0.1.1

2 files

0.1.0

2 files

0.0.1

2 files

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page