Compare commits
45
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
07dda2bfa2 | ||
|
|
b09a907747 | ||
|
|
d167ba927c | ||
|
|
37b4e690cf | ||
|
|
701442d4d4 | ||
|
|
be149cd6f7 | ||
|
|
376653135b | ||
|
|
ce7279e68f | ||
|
|
8dc84f88e9 | ||
|
|
18aef2a459 | ||
|
|
9254c17316 | ||
|
|
b0dcb17e1a | ||
|
|
9756db3204 | ||
|
|
11fd0e2dc2 | ||
|
|
f92a86f5d8 | ||
|
|
fb7ea846ff | ||
|
|
46ac0a7a20 | ||
|
|
fc905fe6bd | ||
|
|
3228b1e0d7 | ||
|
|
b4dadd82b3 | ||
|
|
7c73d392b9 | ||
|
|
78a5cfd8d7 | ||
|
|
7f0a739213 | ||
|
|
7f66015ac8 | ||
|
|
8afdabc7d1 | ||
|
|
48252b1dcd | ||
|
|
01ff919859 | ||
|
|
c121c42e39 | ||
|
|
c61d9c95c9 | ||
|
|
761a2331f5 | ||
|
|
f259bd34e1 | ||
|
|
b95ce798b4 | ||
|
|
04eff611e7 | ||
|
|
68f3eefeca | ||
|
|
152479b350 | ||
|
|
ceb0f35418 | ||
|
|
440d95cad8 | ||
|
|
f1b50ad91a | ||
|
|
78b6267d3a | ||
|
|
59fb06304f | ||
|
|
e291058754 | ||
|
|
aba2aebeb0 | ||
|
|
a324fd57b7 | ||
|
|
e978e878df | ||
|
|
23415fbcd0 |
@@ -1,2 +1,4 @@
|
||||
__pycache__/
|
||||
*.pyc
|
||||
web/node_modules
|
||||
.venv311/
|
||||
|
||||
@@ -68,10 +68,20 @@ routing:
|
||||
|
||||
# ---- 预算 ----
|
||||
# 没有预算控制的架构,在第一个月账单出来时就会崩。
|
||||
# HEL-882:请求次数硬顶与 token 一样是真实硬闸(发送前原子预占,到顶拒绝,
|
||||
# 重启不归零)。以下数值全部是「未批准」的 fail-closed 默认:执行表
|
||||
# docs/budget-plan-hel874.md A/C 部分待批上限不构成批准,批准前一律 0=拒绝。
|
||||
budget:
|
||||
daily_tokens: 2000000
|
||||
warn_ratio: 0.7
|
||||
hard_stop_ratio: 0.95
|
||||
daily_requests:
|
||||
dialogue: 0 # 主对话+主动措辞+危机(C 表建议 60/日,待批)
|
||||
life: 0 # 生活事件生成(C 表建议 8/日,待批)
|
||||
background: 0 # gist/判定/成长(C 表建议 40/日,待批)
|
||||
semantic: 0 # Mem0 提取 LLM(C 表建议 40/日,待批)
|
||||
# total_requests: 55 # A 部分一次性团队检查总请求硬顶(待批,由总管填)
|
||||
# total_tokens: 500000 # A 部分一次性总 token 硬顶(待批,由总管填)
|
||||
|
||||
# =============================================================================
|
||||
# 语音链路
|
||||
|
||||
@@ -1,24 +1,61 @@
|
||||
# CyberGril 语义记忆层(Mem0 固定源)脱敏配置示例
|
||||
#
|
||||
# 复制为 config/semantic.yaml 并由总管在获批准的预算数值内填写。
|
||||
# embed_cap=0 是安全默认:真实嵌入通道保持关闭(fail-closed),任何调用都会被拒绝,
|
||||
# 不会碰 498/500 的冻结余额。只有白栖知批准的新预算经总管核定后才可调高。
|
||||
# embed_cap=0 / llm_cap=0 是安全默认:真实嵌入与 SDK 内部提取 LLM 全部关闭
|
||||
# (fail-closed,任何真实工作前拒绝),不会碰 498/500 的冻结余额。只有白栖知
|
||||
# 批准的新预算经总管核定后才可调高。硬闸与执行表见 docs/budget-plan-hel874.md。
|
||||
#
|
||||
# 后端选择(环境变量 CYBERGRIL_SEMANTIC):
|
||||
# off —— 关闭(默认;对话记忆检索回落到 R3 词面 FTS 通道)
|
||||
# stub —— 编排接通的自测后端(确定性子串匹配,非语义,不冒充语义能力)
|
||||
# mem0 —— 真实固定源 Mem0(2c81af3bbe27d9bccb09c772d583df9e9be72ee5,mem0ai 2.2.1,
|
||||
# 需已安装的固定 venv,见 docs/runbook-hel870.md)
|
||||
# 需发布 venv 已离线并入固定栈 wheel,见 deploy/hel874-release.md §4)
|
||||
# HEL-874/882 已对固定安装实测:search 必须带 user_id 过滤、payload 直读走
|
||||
# SDK 自带 client、内部 LLM 过独立 llm_ops 闸(证据 docs/rework/hel874/)。
|
||||
|
||||
# 嵌入账本:沿用 HEL-857 系列唯一权威账(embed_ops 表)续账,绝不另起新账
|
||||
# 嵌入账本:沿用 HEL-857 系列唯一权威账(embed_ops 表)续账,绝不另起新账;
|
||||
# SDK 内部提取 LLM 记同库 llm_ops 新表(独立 cap,互不挪用)
|
||||
#
|
||||
# ── 累计上限算式(HEL-885,写入前照此换算,禁止直接填增量)───────────────
|
||||
# 权威账现状:已用 498 条 / 原批上限 500(其中冻结不动 2 条余额)。
|
||||
# 白栖知批准的 B 部分新增嵌入额度(例如 180 条)并入同一累计账:
|
||||
# embed_cap = 500 + 180 = 680 # 原上限 + 新批增量(不是 180!)
|
||||
# embed_reserve = 2 # 原冻结余额 2 条继续保留不动
|
||||
# 可用余量 = 680 − 498 − 2 = 180
|
||||
# 错误示例:embed_cap: 180(对已用 498 的账等于瞬间耗尽并掩盖历史);
|
||||
# 动到旧冻结 2 条(min_used: 498 会拒绝)。
|
||||
ledger_path: /absolute/path/to/embed_ledger.sqlite3
|
||||
embed_cap: 0 # 本产品环境允许使用的嵌入条数上限;0=未批准=全部拒绝
|
||||
embed_reserve: 0 # 预留不动的余量(例如为复测保留 40)
|
||||
embed_cap: 0 # 本产品环境允许使用的嵌入条数累计上限;0=未批准=全部拒绝
|
||||
embed_daily: 0 # 嵌入条数日顶(执行表 C:建议 60/日,待批);0=未批准=拒绝
|
||||
embed_reserve: 0 # 预留不动的余量(例如为复测保留 40;冻结口径见上方算式)
|
||||
llm_cap: 0 # Mem0 内部提取 LLM 调用累计上限(执行表 B:建议 60,待批)
|
||||
llm_daily: 0 # Mem0 内部提取 LLM 日顶(执行表 C:建议 40/日,待批)
|
||||
|
||||
# 冻结前缀(HEL-885 起为必填,不可注释掉):只要 embed_cap / llm_cap 任一 >0,
|
||||
# 缺少、留空或填错的 authority 块都会让 mem0 模式在构造前直接拒绝
|
||||
# (ledger_authority_required / ledger_authority_*,fail-closed,不降级)。
|
||||
# ledger_path 必须仍是含冻结前缀的权威账——指向新空文件重开余额同样被拒。
|
||||
# 数值由总管按权威账现状填写(前 N 行逐行 SHA256 与最少已用条数):
|
||||
authority:
|
||||
prefix_rows: 181
|
||||
prefix_sha256: "<权威账前 N 行逐行摘要,总管填写>"
|
||||
min_used: 498
|
||||
|
||||
# 记录作用域:add(user_id=) 与 search(filters={"user_id":…}) 必须一致;
|
||||
# mem0 2.2.1 拒绝无过滤 search,此键一般不需要改
|
||||
user_scope: cybergril
|
||||
|
||||
# 网关(现有配置同源,config/models.yaml 的 halogen 网关)
|
||||
gateway_base_url: http://192.168.200.11:8731/v1
|
||||
gateway_model: halogen-qwen3.8-flash-next
|
||||
gateway_key: cybergril-local-test
|
||||
# 每次网关调用的硬超时(秒,HEL-889):关闭排空阶段因此有界——已被接受但
|
||||
# 长期不答的请求不会把 worker 与进程关闭无限挂住。默认 60,一般不改。
|
||||
gateway_timeout: 60
|
||||
|
||||
# 统一请求闸:产品进程会把 router 的 PersistentBudget 传给后端,SDK 内部提取
|
||||
# LLM 每次发送前在 "semantic" 类别 + 日 token 池里原子预占(models.yaml 的
|
||||
# daily_requests.semantic 与 daily_tokens 批准值生效),无需在此重复配置。
|
||||
|
||||
# 本地向量库与推导史目录(独立数据目录,随实例一起备份/回滚)
|
||||
vector_root: /absolute/path/to/sem/vec
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
# CyberGril 语音会话端点脱敏配置示例(HEL-877,R5 后台施工)
|
||||
#
|
||||
# 复制为 config/voice.yaml(或用 CYBERGRIL_VOICE_CONFIG 指定路径)后由总管
|
||||
# 按部署值填写;api_key/api_secret 只写服务器本地文件,不进仓库、不进浏览器、
|
||||
# 不进任何日志。环境变量 CYBERGRIL_VOICE_* 可覆盖同名字段。
|
||||
#
|
||||
# 没有这份文件 = 本实例未配置语音:POST /api/voice/session 如实 503 拒绝,
|
||||
# /api/health 的 capabilities.voice 保持 false,不伪造已接通。
|
||||
|
||||
# LiveKit SFU(.12 已有 docker voice-livekit;浏览器接入地址)
|
||||
# 注意:7880 是纯 ws 且被通用 worker/8090 共享,不得改 TLS。页面走 HTTPS 时
|
||||
# 浏览器连 ws:// 属混合内容会被拦——R5 方案是独立的 TLS 桥(拟议,未部署):
|
||||
# deploy/voice/wss_bridge.example.py,livekit_url 用 wss://192.168.200.12:8363
|
||||
# (详见 docs/rework/hel879/unified-review/r5-test-package.md §3)。
|
||||
livekit_url: ws://192.168.200.12:7880
|
||||
# 服务端 Twirp 调用地址(本机回环即可)
|
||||
livekit_internal: http://127.0.0.1:7880
|
||||
# LiveKit API 凭据(与 .12 /opt/voice-agent/.env 中 LIVEKIT_KEYS 同源;此处只放占位符)
|
||||
api_key: <LIVEKIT_API_KEY_PLACEHOLDER>
|
||||
api_secret: <LIVEKIT_API_SECRET_PLACEHOLDER>
|
||||
|
||||
# 专属 worker 的 agent_name:与通用 cascade-voice-agent 区分派发,互不争抢
|
||||
agent_name: cybergril-voice-agent
|
||||
|
||||
# CosyVoice TTS 健康探测(TTS 不在就诚实拒绝开通话,不假装能说话)
|
||||
tts_health_url: http://127.0.0.1:9880/health
|
||||
|
||||
# ---- 自定义音色(HEL-899)----
|
||||
# .12 语音面板(8090,https 自签):音色列表/zero-shot 登记的唯一写入者,
|
||||
# CyberGril 统一 API 服务端代理调用;浏览器永不直连,凭据不外发。
|
||||
panel_url: https://127.0.0.1:8090
|
||||
# CosyVoice 合成入口(试听现合成;/health 的热加载名单用于通话开启时校验)
|
||||
tts_url: http://127.0.0.1:9880
|
||||
# 共享 voices.json 只读回看(补全 ASR 自动转写的参考文本,供备份清单);不配则留空
|
||||
registry_file: /opt/voice-agent/cosyvoice/voices.json
|
||||
# CyberGril 专属 worker 的音色状态文件(worker 会话入口读一次;通话中改选最迟下一通话生效)
|
||||
worker_state_file: /opt/voice-agent-cybergril/voice_state_cybergril.json
|
||||
|
||||
# 浏览器接入 token 有效期(秒):只够加入房间,短时限
|
||||
token_ttl_seconds: 300
|
||||
# 会话登记有效期(秒):房间早空/挂断后登记自然过期
|
||||
session_ttl_seconds: 7200
|
||||
@@ -0,0 +1,40 @@
|
||||
# Review/install by 总工 only. HEL-874/882 isolated unified candidate, port 8360.
|
||||
# Fresh EMPTY data dir — never the 8300/8310/8320/8340/8350 dirs, never demo data.
|
||||
# CYBERGRIL_SEMANTIC stays stub until Part-B budget approval AND the pinned mem0
|
||||
# stack wheels are staged for 3.11 (deploy/hel874-release.md §4); not presenting a
|
||||
# stub/FTS fallback as the user's real memory experience.
|
||||
# HEL-882: PYTHONPATH makes the product importable from the requirements.lock-only
|
||||
# venv (deps only, no editable install); budget request caps ship at 0 = refuse
|
||||
# every real provider exit until the manager writes approved numbers (see
|
||||
# config/models.yaml budget block + docs/budget-plan-hel874.md).
|
||||
[Unit]
|
||||
Description=CyberGril HEL-874 unified candidate (isolated, R4-assembly)
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=cybergril
|
||||
Group=cybergril
|
||||
WorkingDirectory=/opt/cybergril-hel874/current
|
||||
Environment=PYTHONPATH=/opt/cybergril-hel874/current/src
|
||||
Environment=CYBERGRIL_DB=/opt/cybergril-hel874/data/companion.db
|
||||
Environment=CYBERGRIL_MODELS=/opt/cybergril-hel874/current/config/models.yaml
|
||||
Environment=CYBERGRIL_WEB=/opt/cybergril-hel874/current/web/dist
|
||||
Environment=CYBERGRIL_R2_ENABLED=1
|
||||
Environment=CYBERGRIL_SEMANTIC=stub
|
||||
Environment=CYBERGRIL_HOST=0.0.0.0
|
||||
Environment=CYBERGRIL_PORT=8360
|
||||
ExecStart=/opt/cybergril-hel874/current/.venv311/bin/python -m cybergril.api
|
||||
Restart=on-failure
|
||||
RestartSec=3
|
||||
TimeoutStopSec=15
|
||||
UMask=0077
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
ReadWritePaths=/opt/cybergril-hel874/data
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
@@ -0,0 +1,156 @@
|
||||
# HEL-874/882 · 8360 隔离发布包(离线核验过,未执行部署)
|
||||
|
||||
**状态:审核通过与预算批准前不启动面向用户的真实循环、不部署、不合并 PR、
|
||||
不向用户交体验地址。**本文件是发布卡照抄即可执行的包;不触 8300/8310/8320/
|
||||
8340/8350 与共享 ASR/TTS/口型,不访问 4080,不导入演示/测试档案为用户伴侣。
|
||||
|
||||
HEL-882 修正:空目录 checkout、服务 import(PYTHONPATH)、服务账号/权限、
|
||||
mem0 同进程导入的准确缺项与不下载解决路径、空账初始化、请求上限随包默认 0。
|
||||
离线核验命令见 §6(tools/check_release_offline_hel882.py,仅回环、echo 替身、
|
||||
临时目录,零真实网关请求)。
|
||||
|
||||
## 1. 交付物清单
|
||||
|
||||
- 代码:分支 `hel-870-assembly`(PR #11,head 见交付评论),含
|
||||
`deploy/cybergril-hel874-8360.service.example`、`tools/check_release_offline_hel882.py`
|
||||
与本文件。
|
||||
- 依赖:Python 3.11 + `requirements.lock`(uv 离线可装);前端 `web/` 原作者
|
||||
构建产物(`npm ci && npm run build`);语义真实模式另需固定 mem0 栈(§4,
|
||||
需先落 wheel,当前缓存没有 3.11 版)。
|
||||
|
||||
## 2. 安装命令(发布卡执行)
|
||||
|
||||
> **已被取代(HEL-879,2026-10-27)**:本节安装命令缺 `--offline`/`--no-index`
|
||||
> 强制项。唯一照抄入口改为 `deploy/hel895-release-candidate.md` §2。本文件其余
|
||||
> 内容作为历史交付证据保留原样。
|
||||
|
||||
```bash
|
||||
# 全新目录,逐条照抄;任何一步失败即停
|
||||
# 2.1 服务账号与目录(独立可写数据路径,权限边界明确)
|
||||
useradd --system --home-dir /opt/cybergril-hel874 --shell /usr/sbin/nologin cybergril || true
|
||||
mkdir -p /opt/cybergril-hel874/data # data 必须为空:新账从零初始化
|
||||
chown -R cybergril:cybergril /opt/cybergril-hel874
|
||||
|
||||
# 2.2 代码 checkout:current 必须是全新空目录后 clone(空目录里没有仓库,
|
||||
# 不能直接 git fetch —— HEL-882 修正)
|
||||
git clone ssh://git@192.168.200.36:222/leefer/CyberGril.git /opt/cybergril-hel874/current
|
||||
git -C /opt/cybergril-hel874/current checkout <交付评论中的精确head>
|
||||
|
||||
# 2.3 依赖与前端(复用 uv/npm 离线缓存;缓存缺失时此步需要内网源,发布卡留证)
|
||||
cd /opt/cybergril-hel874/current
|
||||
uv venv --python 3.11 .venv311
|
||||
uv pip install --python .venv311/bin/python -r requirements.lock
|
||||
(cd web && npm ci && npm run build)
|
||||
|
||||
# 2.4 服务单元(单元内已带 PYTHONPATH=<current>/src:requirements.lock 只装依赖,
|
||||
# 产品代码经 PYTHONPATH 进程内可 import —— HEL-882 修正)
|
||||
cp deploy/cybergril-hel874-8360.service.example /etc/systemd/system/cybergril-hel874.service
|
||||
systemctl daemon-reload && systemctl enable --now cybergril-hel874
|
||||
curl -s http://127.0.0.1:8360/api/health | python3 -m json.tool
|
||||
```
|
||||
|
||||
随包 `config/models.yaml` 的请求上限全部为 0(未批准即拒绝):在总管写入批准
|
||||
值(A 部分一次性总量或 C 部分类别日顶)之前,创建/对话/生活/gist/主动措辞/
|
||||
Mem0 提取都会在发送前被硬闸拒绝(`budget_*_exhausted`)——这是设计行为,
|
||||
不是故障;批准值的写入位置与口径见 `docs/budget-plan-hel874.md`。
|
||||
|
||||
## 3. 健康能力矩阵(/api/health 预期)
|
||||
|
||||
| 字段 | 预期 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| version | `R4-assembly` | |
|
||||
| backend.mood / reach_out / semantic | true | 情绪/关系/生活/主动联系接线 |
|
||||
| backend.semantic_backend | `stub`(发布初期) | 真实 mem0 待 B 部分预算批准(§4) |
|
||||
| capabilities.proactive | true | 生活循环开启时 |
|
||||
| capabilities.semantic_memory | `stub` | 不冒充语义 |
|
||||
| voice / vision / weather / materials / backup | false | 界面诚实文案,不伪装 |
|
||||
|
||||
## 4. 真实语义激活前置(B 部分批准后;准确缺项与不下载路径)
|
||||
|
||||
> **已被取代(HEL-879,2026-10-27)**:本节 4.1/4.2 按索引拉 `mem0ai==2.2.1`
|
||||
> 同名 wheel,不能保证固定源码身份 2c81af3;固定 SDK 激活的唯一照抄入口改为
|
||||
> `deploy/hel895-release-candidate.md` §4(固定 tarball 哈希 → 固定源码构建轮 →
|
||||
> cp311 依赖准备 → 仅本地轮安装 → 同进程 co-import)。以下保留为历史证据。
|
||||
|
||||
**当前事实(HEL-882 离线核实,tools/check_release_offline_hel882.py R6):**
|
||||
固定安装 hel857-venv 是 Python 3.10.12,产品发布 venv 是 3.11.16,两者
|
||||
site-packages 不能混用;本机 uv/pip 缓存里没有 mem0ai/fastembed/qdrant-client
|
||||
的 3.11 wheel,本卡不下载。因此发布卡要在 **B 部分批准后** 先落 wheel 再激活。
|
||||
|
||||
**HEL-885 命令勘误:旧版此处的 `uv pip download …` 在本机 uv(0.13.5)不存在
|
||||
(`uv pip download --help` 退出 2:unrecognized subcommand 'download',已复测,
|
||||
见 docs/rework/hel885/)。本机确实可用的落 wheel 工具是 pip 的 download 子命令
|
||||
(`python3 -m pip download --help` 退出 0)。发布 venv 由 uv 创建、不带 pip,
|
||||
这不影响:下载在任一装有 pip 的 Python 上执行即可,wheel 按目标平台解析。**
|
||||
|
||||
```bash
|
||||
# 4.1 在有内网源权限的环境把固定栈拉全(发布卡执行并留证;不在本卡执行、
|
||||
# 不下载)。先核对目标机平台:uname -m 必须与 --platform 一致(当前
|
||||
# 部署机为 x86_64 Linux)。
|
||||
uname -m # 预期 x86_64;不符则改 --platform
|
||||
mkdir -p /opt/cybergril-hel874/wheels
|
||||
python3 -m pip download -r deploy/mem0-stack.lock -d /opt/cybergril-hel874/wheels \
|
||||
--only-binary :all: --implementation cp --python-version 3.11 \
|
||||
--platform manylinux2014_x86_64 --abi cp311
|
||||
# 4.1b 固定源身份与哈希留证:下载当时逐 wheel 记录 sha256(与发布评论一并
|
||||
# 存档;mem0ai 的源码身份 2c81af3 / tarball SHA256 见 deploy/mem0-stack.lock
|
||||
# 注释——如需从源码 tarball 侧核对,比对 lock 注释中的值)。
|
||||
sha256sum /opt/cybergril-hel874/wheels/*.whl | tee /opt/cybergril-hel874/wheels/SHA256SUMS
|
||||
# 4.2 同一发布进程离线并入(一个 venv 同时 import 产品与 mem0 —— 唯一被认可形态;
|
||||
# uv pip install 是本机确实存在的子命令,--no-index 离线装)
|
||||
uv pip install --python .venv311/bin/python --no-index \
|
||||
--find-links /opt/cybergril-hel874/wheels -r deploy/mem0-stack.lock
|
||||
.venv311/bin/python -c "import cybergril.api, mem0, qdrant_client, fastembed; print('co-import ok')"
|
||||
```
|
||||
|
||||
**准确缺项与如实上报(HEL-885):** 本机当前没有这些 3.11 wheel,本卡零下载,
|
||||
`wheels/` 目录与 SHA256SUMS 均不存在——发布卡执行 4.1 时才能产生。若某个固定
|
||||
版本在 cp311/manylinux2014_x86_64 没有 wheel(`--only-binary :all:` 会直接报错
|
||||
指出包名),按 lock 注释如实上报缺项,不得换版本号冒充固定安装、不得改用 sdist
|
||||
混装。4.2 的 co-import 是最终判据:任何一个 import 失败即未完成,不得以 stub/
|
||||
FTS 降级包冒充用户的真实完整记忆体验(体验交付必须等本节全部完成 + 新增预算
|
||||
批准)。发布前可先跑 `python3 tools/check_release_offline_hel882.py` 的 R7
|
||||
核验本节两条命令的工具面(pip download 存在、uv pip download 不存在)。
|
||||
|
||||
激活步骤(wheel 落好之后):
|
||||
|
||||
1. `cp config/semantic.example.yaml config/semantic.yaml`,总管填批准值:
|
||||
`embed_cap`/`llm_cap`(B 部分累计,换算算式见示例文件与执行表 §2——
|
||||
500+增量,不是把增量直接填进累计上限)、`embed_daily`/`llm_daily`
|
||||
(C 部分日顶)、`embed_reserve`;`ledger_path` 指向唯一权威
|
||||
`embed_ledger.sqlite3` 续账(`llm_ops` 同库新表),并**填写** `authority`
|
||||
冻结前缀块(HEL-885 起必填:缺/空/错一律在构造前拒绝
|
||||
`ledger_authority_required`,指向新空文件绕过 498/500 冻结同样被拒)。
|
||||
2. `CYBERGRIL_SEMANTIC=mem0` 重启。任何未批调用 fail-closed
|
||||
(`semantic_*_budget_not_approved/exhausted/daily_exhausted`);SDK 内部
|
||||
提取 LLM 同时过统一请求闸(`semantic` 类别 + 日 token 池,发送前预占)。
|
||||
|
||||
## 5. 停用与保留数据回退
|
||||
|
||||
- 停语义层:`CYBERGRIL_SEMANTIC=off`(或 stub)重启;`sem_batch/sem_covered/
|
||||
sem_row_done` 按后端区分保留,重开续跑不重发已完成行(逐行锚点+逐行完成
|
||||
记录,HEL-885),stub 批次不阻塞真实重建。
|
||||
- 停主动联系/生活:`CYBERGRIL_R2_ENABLED=0`。
|
||||
- 整实例回退:`systemctl stop cybergril-hel874` → 数据目录
|
||||
`/opt/cybergril-hel874/data/` 原样保留(聊天/记忆/生活/情绪/关系全量 +
|
||||
请求/token 硬闸计数,SQLite WAL 单文件可整体复制)→ 切回上一 release /
|
||||
上一提交。R4 迁移全部为增量新表(r4.sql:语义/活动/主动/硬闸计数),
|
||||
旧代码可安全打开同一数据库。
|
||||
- 彻底撤销:`systemctl disable --now cybergril-hel874 && rm /etc/systemd/system/
|
||||
cybergril-hel874.service`;数据目录留档不删(用户资料不重置边界)。
|
||||
|
||||
## 6. 发布前必过检查(发布卡执行并留证)
|
||||
|
||||
1. 离线可执行检查(本卡已跑通,证据见交付评论;发布卡在目标机重跑):
|
||||
`python3 tools/check_release_offline_hel882.py --venv <发布venv>/bin/python`
|
||||
—— R1 空目录 checkout、R2 服务 import+health、R3 未批上限 fail-closed、
|
||||
R4 批准后全链(echo 替身)、R5 停止后数据保留/重开 epoch+1、
|
||||
R6 mem0 同进程导入现状(缺什么、怎么补,§4)。
|
||||
2. `python3 scripts/check_requirements.py --base-ref origin/main --handoff
|
||||
docs/requirements/handoff-HEL-882.json` 及 `--base-ref
|
||||
origin/agent/agent/de8874a3803b`(双目标各含/不含 handoff)。
|
||||
3. 3.11 venv 全量 pytest + ruff + web typecheck/test/build。
|
||||
4. 隐私负例(未分享伴侣行不出现在任何 provider 输入/DTO/页面)与重开恢复
|
||||
(epoch+1、消息一致、主动消息带标记)。
|
||||
5. A 部分预算未批前:`semantic.yaml` 缺省即 cap=0,`/api/health` 的
|
||||
semantic_backend 必须仍为 stub;`models.yaml` 请求上限未批前必须全 0。
|
||||
@@ -0,0 +1,233 @@
|
||||
# HEL-895 · 统一发布候选(离线核验过,未执行部署)
|
||||
|
||||
> **HEL-879 发布工具收口(2026-10-27,隔离候选分支 `hel-879-assembly`)**:按总管
|
||||
> 对 HEL-896 的独立复核完成四项有限收口——①归档一致性:checkpoint 返回值必查、
|
||||
> 源/快照行数不一致或 checkpoint busy 一律 CLI 非 0 且不形成可交付包,verify 拒绝
|
||||
> 记录了 `rows_match=False` 的旧包(§5);②目录内真实 SQLite(history_root 的
|
||||
> `mem0_public_history.db` 等)停服口径走 checkpoint+逐表核对,在线模式只允许显式
|
||||
> 单库 backup API、含 SQLite 的目录直接拒绝;③提前封账:`tools/seal_budget_hel879.py`
|
||||
> 显式封账(真实用量保留、跨重启/归档拒绝,负例 S6);④安装入口唯一化:本文件 §2/§4
|
||||
> 为唯一照抄入口(全 offline/no-index;mem0ai 只认固定源码轮),`deploy/hel874-release.md`
|
||||
> §2/§4 已标注被取代。产物清单与精确提交见 `docs/rework/hel879/sdk-audit/` 与
|
||||
> `docs/rework/hel879/release-artifacts.json`。**不要用旧父提交(04eff61/152479b)
|
||||
> 的说明冒充本候选 head:以交付评论与 handoff JSON 记录的精确提交为准。**
|
||||
|
||||
> **HEL-896 修订(2026-10-27,正常追加 PR#11)**:按总管独立复审补齐——①浏览器
|
||||
> 「真实服务 7/7」中 B3 原为已证实误报,测试已修为精确交互+严格断言(9 项检查,
|
||||
> 含权限 API 调用计数与非回环出站守卫,证据 `docs/rework/hel896/browser/`);
|
||||
> ②A/B/C 预算改为独立团队测试实例 + 全新用户实例的可执行分账
|
||||
> (`docs/budget-package-hel895.md` §6);③固定 SDK 缺项勘误为 41 项闭包清单
|
||||
> (§4);④归档/回退改为一致性快照口径(§5)。候选 head 与交付物不变,未部署、
|
||||
> 未合并、未写权威账。
|
||||
|
||||
**状态:候选。审核通过与预算/部署授权前不启动面向用户的真实循环、不部署、不合并
|
||||
PR、不交体验地址。** 本文件把已通过独立复审的内核(HEL-894 @ `152479b`)与
|
||||
HEL-881 已审核的主动留言前端(`bf234570`)装成一个统一候选,给出精确 head、
|
||||
交付物清单、安装命令、健康矩阵与停用回退。发布卡照抄即可执行;不触 8300–8350
|
||||
与共享 ASR/TTS/口型,不访问 4080,不导入演示/测试档案为用户伴侣。
|
||||
|
||||
## 0. 精确 head 与整合方式
|
||||
|
||||
> **HEL-879 返修勘误(2026-10-27)**:本节以下原文记录的是 **HEL-895/896 历史
|
||||
> 候选**(分支 `hel-870-assembly`,PR #11 未合并),其 299 pytest / 55 vitest 等
|
||||
> 验证数字属于那个历史 head,**不是当前发布候选**。当前统一发布候选是分支
|
||||
> `hel-879-assembly`(在 7f0a739 之后正常追加返修提交,不强推、不并入 PR #11),
|
||||
> 其精确 head、pytest/vitest/build 全量数字与证据以**交付评论与
|
||||
> `docs/requirements/handoff-HEL-879.json` 记录为准**;本文件的安装/检查入口
|
||||
> (§2/§4/§5/§6)继续适用于当前候选,产物清单见
|
||||
> `docs/rework/hel879/sdk-audit/` 与 `docs/rework/hel879/release-artifacts.json`
|
||||
> (`rework_head` 字段)。历史叙述保留原样,不冒充、不改写。
|
||||
|
||||
- **候选 head**:见交付评论(分支 `hel-870-assembly`,PR #11 的正常追加提交,
|
||||
未强推、未合并)。第一父为 HEL-894 通过复审的 `152479b3503c3d1ab27681170e6bfd592c54380a`,
|
||||
合并入 HEL-881 已审核的 `bf234570c0b6595a72f8dbc79e42c63685e08e01`
|
||||
(origin/hel-880-inbox-continuation,与 origin/hel-875-proactive-wiring 同点)。
|
||||
- **整合的机械性**:母线 `31970c4..152479b` 从未触碰 `web/`(`git diff 31970c4
|
||||
152479b -- web/` 为空),合并只带入原作者六个前端文件与
|
||||
`handoff-HEL-875/880.json` 共 9 个文件;`src/tests/tools/config` 相对 `152479b`
|
||||
逐字不变。无重设计、无视觉决定;旧 `b48d28b` 测试合并未推送,由本候选取代。
|
||||
- **合成后验证(全部在本 head 实跑)**:299 pytest(3.11.16 venv +
|
||||
requirements.lock 离线)+ ruff 干净;web typecheck 0 错、lint 0 错/1 条既有警告、
|
||||
vitest 55/55、build 通过且 CSS 仍为 `index-DdDYzR5S.css`(视觉零改动);
|
||||
固定 SDK 回归:关闭所有权 16/16、关闭排队 12/12、处理中生命周期 6/6、语义恢复
|
||||
7/7、真实接线 12/12;发布离线检查 15/15;**真实 HTTP 分页合同 7/7**
|
||||
(`tools/verify_http_pagination_hel895.py`,真实服务 + 327 行播种 + fetchAfter
|
||||
缺口游标移植对真实后端复验);**真实服务浏览器 7/7**(`web/tests/hel895_real.mjs`,
|
||||
Chromium CDP 对真实 API:留言卡、舞台播放、260 行缺口不跳留言、重启 epoch 去重、
|
||||
零权限申请。**HEL-896 勘误:原 7/7 中 B3 为已证实误报**——兜底断言+点击
|
||||
「日子与回忆」导航钮,`stage=false` 仍 PASS;修订版改精确交互+严格断言共 9 项
|
||||
检查全过,含权限 API 调用计数 0 与非回环出站守卫 0,证据
|
||||
`docs/rework/hel896/browser/`,原误报证据保留于 `docs/rework/hel896/browser-before/`)。双目标及实际母线需求检查各含/不含
|
||||
handoff-HEL-895 共 6/6 通过(origin/main、原产品目标 de8874a3803b、实际母线)。
|
||||
|
||||
## 1. 交付物清单
|
||||
|
||||
| 交付物 | 位置/来源 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 代码 | 分支 `hel-870-assembly`,精确 head 见交付评论 | 含本文件、`docs/budget-package-hel895.md`、`tools/verify_http_pagination_hel895.py`、`web/tests/hel895_real.mjs` |
|
||||
| Python 依赖 | `requirements.lock`(19 项固定版本,uv 离线可装) | Python 3.11(发布机 3.11.16 实测) |
|
||||
| 前端产物 | `web/`(原作者界面 + HEL-875/880 主动留言) | `npm ci && npm run build`;CSS 哈希与已审核版一致 |
|
||||
| mem0 固定栈 | `deploy/mem0-stack.lock`(mem0ai 2.2.1 / qdrant-client 1.20.0 / fastembed 0.9.1) | **3.11 缺 41 项闭包,见 §4;缺项不阻塞其余发布** |
|
||||
| systemd 模板 | `deploy/cybergril-hel874-8360.service.example`(PYTHONPATH=src 已内置) | 独立单元/端口/数据目录模式 |
|
||||
| 配置模板 | `config/models.yaml`(预算全 0)+ `config/semantic.example.yaml` | 批准值写入位置见 `docs/budget-package-hel895.md`(A 仅团队实例,§6) |
|
||||
| 预算执行包 | `docs/budget-package-hel895.md`(含 §6 HEL-896 分账修订) | A/B/C 一次批准核定稿,默认 0 |
|
||||
| HEL-896 工具 | `tools/verify_budget_split_hel896.py`、`tools/audit_sdk_offline_hel896.py`、`tools/release_snapshot_hel896.py`、修订版 `web/tests/hel895_real.mjs` | 分账切换验证、SDK 余缺只读审计、一致性快照/回退验证、严格浏览器检查 |
|
||||
|
||||
## 2. 安装命令(发布卡执行;本节是唯一照抄入口——HEL-879 收口)
|
||||
|
||||
```bash
|
||||
# 全新目录,逐条照抄;任何一步失败即停。全部安装强制 offline/no-index:
|
||||
# 缓存命中即装,缓存缺失即停并留证;联网补齐只发生在获批的发布窗口内,
|
||||
# 逐项 sha256 留证(seq48–51 勘误教训:不写 offline 的安装发生过网络获取)。
|
||||
# 2.1 服务账号与目录(独立可写数据路径,权限边界明确)
|
||||
useradd --system --home-dir /opt/cybergril-hel874 --shell /usr/sbin/nologin cybergril || true
|
||||
mkdir -p /opt/cybergril-hel874/data # data 必须为空:新账从零初始化
|
||||
chown -R cybergril:cybergril /opt/cybergril-hel874
|
||||
|
||||
# 2.2 代码 checkout:全新空目录 clone(空目录里没有仓库,不能直接 git fetch)
|
||||
git clone ssh://git@192.168.200.36:222/leefer/CyberGril.git /opt/cybergril-hel874/current
|
||||
git -C /opt/cybergril-hel874/current checkout <交付评论/handoff JSON 记录的精确head>
|
||||
|
||||
# 2.3 依赖与前端(uv/npm 一律 offline;缓存缺失即停)
|
||||
cd /opt/cybergril-hel874/current
|
||||
uv venv --python 3.11 .venv311
|
||||
uv pip install --python .venv311/bin/python --offline -r requirements.lock
|
||||
(cd web && npm ci --offline && npm run build)
|
||||
|
||||
# 2.4 服务单元(单元内已带 PYTHONPATH=<current>/src:requirements.lock 只装依赖,
|
||||
# 产品代码经 PYTHONPATH 进程内可 import)
|
||||
cp deploy/cybergril-hel874-8360.service.example /etc/systemd/system/cybergril-hel874.service
|
||||
systemctl daemon-reload && systemctl enable --now cybergril-hel874
|
||||
curl -s http://127.0.0.1:8360/api/health | python3 -m json.tool
|
||||
```
|
||||
|
||||
发布前必过检查按 §6 与 `deploy/hel874-release.md` §6 的清单执行(该节仍有效),
|
||||
另加本卡工具(真实 HTTP 分页合同、真实服务浏览器)在目标机重跑。
|
||||
|
||||
## 3. 健康能力矩阵(/api/health 预期)
|
||||
|
||||
与 `deploy/hel874-release.md` §3 一致:`version=R4-assembly`;backend
|
||||
mood/reach_out/semantic 接线;`semantic_backend=stub`(发布初期,真实 mem0 待 §4
|
||||
与 B 部分预算);capabilities.proactive=true(生活循环开启时);voice/vision/
|
||||
weather/materials/backup=false。**主动留言前端已并入本候选:生活循环开启且产生
|
||||
真实 reach-out 后,打开的页面每 20 秒读一次新行、回来立即读,未读有标记;该行为
|
||||
已在本 head 用真实服务验证(§0)。**
|
||||
|
||||
## 4. 固定 SDK(3.11)激活——唯一照抄入口(HEL-879 收口)
|
||||
|
||||
**本节取代 `deploy/hel874-release.md` §4(历史文件,已标注被取代,不得再照抄)。**
|
||||
旧 4.1/4.2 按 `deploy/mem0-stack.lock` 的 `mem0ai==2.2.1` 向索引拉同名 wheel——
|
||||
**索引同名 wheel 不能证明固定源码身份 2c81af3**,这条路已废除。入口只有一条:
|
||||
|
||||
**固定 tarball 哈希 → 固定源码构建轮 → 目标 cp311 依赖准备 → 仅本地轮安装 → 同进程 co-import。**
|
||||
|
||||
- **第 0 步 · 产物清单核对**:`docs/rework/hel879/sdk-audit/sdk-audit.json`(本候选
|
||||
精确提交上重跑)与 `docs/rework/hel879/release-artifacts.json` 记录闭包 55 项、
|
||||
缺 41 项、缓存可复用 3 项与逐项哈希;发布卡先核对清单与目标提交一致。
|
||||
事实口径(HEL-896 审计核定,HEL-879 重跑仍成立):三个顶层固定版本
|
||||
(mem0ai 2.2.1 / qdrant-client 1.20.0 / fastembed 0.9.1)的 wheel 均为
|
||||
`py3-none-any` 纯 Python;闭包按 3.11 Linux markers+extras 共 **55 项,产品
|
||||
3.11 venv 缺 41 项**(28 纯 Python + 13 原生:grpcio/numpy/onnxruntime/
|
||||
tokenizers/sqlalchemy/protobuf 等),这是闭包清单不是已完成的 cp311 下载结果。
|
||||
seq48–51 pip 事件勘误保留:不写 offline 的安装发生过网络获取(uv 缓存取证),
|
||||
故本入口全程 `--offline`/`--no-index`。
|
||||
- **第 1 步 · 固定 tarball 哈希核对**(零下载):
|
||||
```bash
|
||||
sha256sum <hel857-data>/mem0-2c81af3.tar.gz
|
||||
# 必须等于 deploy/mem0-stack.lock 记录的
|
||||
# 9dcef9303ebcec116eec6739f01b8b35bd24459de6a569686b4d19b9412dda23
|
||||
```
|
||||
不一致即停;不得改用索引 `mem0ai==2.2.1` wheel 冒充固定源(audit 已证明两者
|
||||
身份不可互证)。
|
||||
- **第 2 步 · 固定源码构建轮(HEL-879 返修:已完成可离线构建)**:此前此处写
|
||||
「hatchling 当前不在任何本机缓存、待补」——经总管只读核查与本卡复核**勘误**:
|
||||
uv wheels-v6/wheels-v7 均有 hatchling **1.32.4** 缓存(`release-artifacts.json`
|
||||
`build_backend` 节逐路径留证)。固定源 tarball 已在 3.11.16 + `uv build --wheel
|
||||
--offline` 下**离线构建出轮**(零下载、零安装、不混 3.10 site-packages):
|
||||
`mem0ai-2.2.1-py3-none-any.whl`,
|
||||
sha256 `698284b6083ab8b7761454d65876a6d1bb983d278ad21a7bee38d760cb20e9db`。
|
||||
发布卡在目标机重跑同一命令并核对该哈希:
|
||||
```bash
|
||||
tar xzf <hel857-data>/mem0-2c81af3.tar.gz && cd mem0-2c81af3*/
|
||||
uv build --wheel --offline --python 3.11 -o wheels/
|
||||
sha256sum wheels/mem0ai-2.2.1-py3-none-any.whl
|
||||
```
|
||||
- **第 3 步 · 目标 cp311 依赖准备**:41 项缺项中**缓存今天即可复用 3 项**
|
||||
(greenlet 3.5.6 cp311、pillow 12.3.0 cp311、truststore 0.10.5 py3-none-any,
|
||||
uv wheels-v6/v7 缓存实测,HEL-879 重跑核实仍命中);其余 37 项
|
||||
**由总管获批后发布窗口拉取**(`python3 -m pip download --only-binary :all:
|
||||
--implementation cp --python-version 3.11 --platform manylinux2014_x86_64
|
||||
--abi cp311 -r <缺项清单> -d wheels/`),逐项 sha256 留证;本卡零下载、零联网。
|
||||
某固定版本若无 cp311 wheel,按 lock 注释如实上报缺项,不换版本号、不混 sdist。
|
||||
- **第 4 步 · 仅本地轮安装**(--no-index 全程,目录里只有上两步产物):
|
||||
```bash
|
||||
uv pip install --python .venv311/bin/python --no-index \
|
||||
--find-links <本地wheels目录> mem0ai==2.2.1 qdrant-client==1.20.0 fastembed==0.9.1 <41缺项>
|
||||
```
|
||||
`deploy/mem0-stack.lock` 的 mem0ai 行只作版本记录;安装来源必须是第 2 步的
|
||||
固定源码轮(同版本号不同来源不互认)。
|
||||
- **第 5 步 · 同进程 co-import 与模型落位**:
|
||||
```bash
|
||||
.venv311/bin/python -c "import cybergril.api, mem0, qdrant_client, fastembed; print('co-import ok')"
|
||||
```
|
||||
fastembed 模型缓存(hel857-data/fastembed-cache,Qdrant/bge-small-zh-v1.5 +
|
||||
bm25 约 92MB,实测存在)拷入实例数据目录,真实 mem0 模式 cache_dir 指向它。
|
||||
|
||||
产品 venv 目前 `import mem0/qdrant_client/fastembed` 均缺、产品代码导入不受影响;
|
||||
在 wheel 落位且 co-import 通过前,不得以 stub/FTS 冒充真实 Mem0 体验就绪。
|
||||
真缺的下载(37 项运行闭包;hatchling 已勘误为缓存命中并完成离线构建,不在缺单)
|
||||
仍待主卡授权,本卡不为补命令联网。
|
||||
|
||||
## 5. 停用与保留数据回退
|
||||
|
||||
与 `deploy/hel874-release.md` §5 相同:`CYBERGRIL_SEMANTIC=off|stub` 停语义层
|
||||
(表保留、按后端区分续跑);`CYBERGRIL_R2_ENABLED=0` 停生活/主动联系;整实例
|
||||
`systemctl stop` → 数据目录原样保留 → 切回上一 release/上一提交(R4 迁移全部
|
||||
增量新表,旧代码可安全打开同一数据库);彻底撤销留数据档不删。
|
||||
|
||||
**HEL-896 归档/回退修订 + HEL-879 收口(2026-10-27,v3 返修)**:在线库只复制主
|
||||
`.db` 会丢 WAL 里已提交的资料(总管复现件连 `companion` 表都不在)。发布归档一律
|
||||
二选一:**停服务 + `PRAGMA wal_checkpoint(TRUNCATE)` 后整目录归档**(推荐),或
|
||||
**在线用 SQLite backup API 对显式单库做一致性快照**。工具已按收口语义强制执行
|
||||
(v3;v2 的两处已证缺陷由总管独立复核提出并修复):
|
||||
|
||||
- checkpoint 返回 busy≠0 或源/快照行数不一致 → CLI 非 0、不产生可交付归档
|
||||
(「先停服」是前提,不是忽略失败结果的理由);
|
||||
- 目录内真实 SQLite(history_root 的 `mem0_public_history.db`、向量目录内库等,
|
||||
按文件头魔数递归识别)在停服口径一并 checkpoint+逐表核对;
|
||||
- 在线模式只接受显式 `--db`(backup API);传入含 SQLite 的 `--file` 目录直接拒绝;
|
||||
- `verify` 要求**三个计数直接相等**(manifest 源行数 = manifest 快照行数 = 恢复
|
||||
实测;`rows_match` 只是额外约束——v2 的 `rows_match is True or …` 允许记录值
|
||||
绕过源计数比较,源 2/快照 1 仍 ok,已废除);回退演练按源路径映射**实际恢复**
|
||||
到归档旁的持久独立目标树、打开恢复库核对行数与哈希,输出 rollback_plan;
|
||||
- 归档侧目标名无冲突映射:不同目录的同名 `ledger.db` 不再互相覆盖(v2 后写覆盖
|
||||
前写仍先交成功包);同一源重复传入直接拒绝。
|
||||
|
||||
照抄命令:
|
||||
|
||||
```bash
|
||||
# 覆盖范围:产品库(CYBERGRIL_DB)、语义向量目录 vector_root、推导史 history_root、
|
||||
# 权威嵌入账 ledger_path(按部署实例 config/semantic.yaml 实际路径逐项代入)
|
||||
# 停服口径(推荐;目录内 SQLite 一并一致性处理):
|
||||
.venv311/bin/python tools/release_snapshot_hel896.py snapshot \
|
||||
--name <release-或阶段名> --db <产品库> [--db <权威账>] \
|
||||
--file <vector_root> --file <history_root> --out /opt/<实例>/archives/
|
||||
# 在线兜底口径:仅显式单库(backup API),不得传含 SQLite 的目录:
|
||||
.venv311/bin/python tools/release_snapshot_hel896.py snapshot --name <名> \
|
||||
--db <产品库> --out /opt/<实例>/archives/ --online
|
||||
.venv311/bin/python tools/release_snapshot_hel896.py verify --archive <产物>.tar.gz
|
||||
```
|
||||
|
||||
产物含逐文件 SHA256 清单、**代码精确提交**(快照时刻 `git rev-parse HEAD`)、
|
||||
逐表行数核对与回退演练结果;不删档,旧归档永久保留。回退=停服务 → 解包快照到
|
||||
新数据目录(按 rollback_plan 的源路径映射)→ 指回上一 release/上一提交 → 起
|
||||
service → `verify` 通过后交付。本节是**发布归档/回退要求**,不冒充 R6(CG-009
|
||||
每日自动备份/手动完整导出)完成。
|
||||
|
||||
## 6. 本候选不做的事
|
||||
|
||||
不合并任何 PR(PR #11 保持开放待总管/白栖知决定);不部署、不交体验地址;
|
||||
零真实 LLM/嵌入/下载;不触 8300–8350、共享语音口型、GPU/4080;不导入演示测试
|
||||
档案为用户伴侣;不替视觉作者改稿(前端内容以原作者六文件与 CSS 可追溯为准)。
|
||||
R5(HEL-878/879 语音)、R6(天气/素材/完整备份)、R7(有条件视觉观察)未接入,
|
||||
界面保持诚实文案,不冒充已运行。
|
||||
@@ -0,0 +1,13 @@
|
||||
# CyberGril 语义记忆层固定栈清单(HEL-882;B 部分批准后由发布卡拉取)
|
||||
# 固定源:mem0ai 2.2.1(源码提交 2c81af3bbe27d9bccb09c772d583df9e9be72ee5,
|
||||
# tarball SHA256 9dcef9303ebcec116eec6739f01b8b35bd24459de6a569686b4d19b9412dda23)。
|
||||
# HEL-879 唯一安装入口:deploy/hel895-release-candidate.md §4(固定 tarball 哈希 →
|
||||
# 固定源码构建轮 → cp311 依赖准备 → 仅本地轮安装 → 同进程 co-import)。
|
||||
# 本文件的 mem0ai==2.2.1 行只作版本记录——不得按此行向索引拉同名 wheel 冒充固定源
|
||||
# (旧 deploy/hel874-release.md §4 已被取代)。若某包无 3.11 wheel,发布卡须如实
|
||||
# 上报缺项,不得换版本号冒充固定安装。版本来自 hel857-venv 实测安装
|
||||
#(Python 3.10.12 侧 mem0ai 2.2.1 / qdrant-client 1.20.0 / fastembed 0.9.1),
|
||||
# 3.11 侧需同版本 wheel。
|
||||
mem0ai==2.2.1
|
||||
qdrant-client==1.20.0
|
||||
fastembed==0.9.1
|
||||
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env bash
|
||||
# CyberGril 专属语音 worker 运维脚本草案(HEL-877,本卡未执行)。
|
||||
# 用法: bash /opt/voice-agent-cybergril/restart_cybergril.sh [stop|status]
|
||||
# 边界: 只管本 worker(python -m cybergril.voice.worker),绝不匹配通用
|
||||
# worker 的 `agent.py start`,不动 /opt/voice-agent 与 8090/8081。
|
||||
set -u
|
||||
BASE=/opt/voice-agent-cybergril
|
||||
cd "$BASE"
|
||||
VENV=/opt/voice-agent/agent/venv # 复用已装 livekit-agents 1.8.8 的 venv
|
||||
PAT='cybergril.voice.worker start' # 精确匹配本 worker 命令行
|
||||
|
||||
for p in $(pgrep -f "$PAT"); do kill "$p" 2>/dev/null; done
|
||||
sleep 2
|
||||
for p in $(pgrep -f "$PAT"); do kill -9 "$p" 2>/dev/null; done
|
||||
|
||||
if [ "${1:-}" = "stop" ]; then echo "cybergril voice worker stopped"; exit 0; fi
|
||||
if [ "${1:-}" = "status" ]; then
|
||||
pgrep -af "$PAT" || echo "not running"
|
||||
curl -s --max-time 3 "http://127.0.0.1:${CYBERGRIL_WORKER_HEALTH_PORT:-8082}/" \
|
||||
&& echo " <- health" || echo "health port not answering"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
set -a; source "$BASE/.env"; set +a
|
||||
PYTHONPATH="$BASE" nohup "$VENV/bin/python" -m cybergril.voice.worker start > worker.log 2>&1 &
|
||||
echo "cybergril voice worker starting (pid $!)"
|
||||
sleep 18
|
||||
grep -m1 "registered worker" worker.log >/dev/null && echo "OK: worker registered" \
|
||||
|| { echo "FAIL:"; tail -5 worker.log; exit 1; }
|
||||
@@ -0,0 +1,105 @@
|
||||
"""统一 CyberGril 实例单进程双入口启动器(HEL-877 部署草案,本卡未执行).
|
||||
|
||||
HTTP 8360 与 HTTPS 8361(语音页需要 secure context 才能拿麦克风)必须共用
|
||||
同一个 API 进程、同一份 app.state(epoch / chat_lock / store / 语音会话登记)。
|
||||
|
||||
HEL-879 收口(总管复核第 1 项):uvicorn 两个 Server 默认各自进入一次 FastAPI
|
||||
lifespan,导致 epoch 1→2、Store/life/chat_lock 全部被第二次初始化替换——同一个
|
||||
app 对象并不保证只初始化一次。本启动器改为:
|
||||
|
||||
- 应用生命周期由本启动器**独占管理且只进入一次**(`app.router.lifespan_context`);
|
||||
- 两个 uvicorn Server 以 `lifespan="off"` 只负责监听,共享同一份状态;
|
||||
- 任一监听退出(失败/取消/信号)先把另一个也停掉,**再**退出生命周期:
|
||||
绝不出现一边还在接请求、一边已被另一个监听提前关库;循环与资源只关闭一次;
|
||||
- `create_app` 的 lifespan 自带重入门卫:任何二次进入直接报错(fail-closed),
|
||||
防止未来改回 auto 双 Server 时再次静默替换状态。
|
||||
|
||||
自签证书签发命令与回滚步骤见 docs/runbook-hel877-voice.md。
|
||||
|
||||
用法(部署卡执行,先 `cd` 到仓库根并激活 3.11 venv):
|
||||
PYTHONPATH=src python deploy/voice/serve_dual_8360_8361.py \
|
||||
--http-port 8360 --https-port 8361 \
|
||||
--cert /opt/cybergril-voice-certs/cert.pem --key /opt/cybergril-voice-certs/key.pem
|
||||
|
||||
本地离线冒烟(不涉及任何现网/证书变更):
|
||||
PYTHONPATH=src python deploy/voice/serve_dual_8360_8361.py \
|
||||
--http-port 18360 --https-port 18361 --cert <本地测试证书> --key <本地测试密钥>
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import contextlib
|
||||
import os
|
||||
import sys
|
||||
|
||||
import uvicorn
|
||||
|
||||
from cybergril.api.app import create_app
|
||||
|
||||
|
||||
async def serve(http_port: int, https_port: int, cert: str, key: str, app=None) -> None:
|
||||
# ONE app object, ONE lifespan owner: both listeners share state, locks,
|
||||
# epoch and the store. The uvicorn servers never run the app lifespan
|
||||
# themselves (lifespan="off") — the context manager below is its only
|
||||
# owner, so initialization and shutdown each happen exactly once.
|
||||
if app is None:
|
||||
app = create_app()
|
||||
http_server = uvicorn.Server(
|
||||
uvicorn.Config(app, host="0.0.0.0", port=http_port, log_level="info",
|
||||
lifespan="off")
|
||||
)
|
||||
https_server = uvicorn.Server(
|
||||
uvicorn.Config(app, host="0.0.0.0", port=https_port, ssl_certfile=cert,
|
||||
ssl_keyfile=key, log_level="info", lifespan="off")
|
||||
)
|
||||
async with app.router.lifespan_context(app):
|
||||
servers = [asyncio.create_task(http_server.serve()),
|
||||
asyncio.create_task(https_server.serve())]
|
||||
try:
|
||||
done, pending = await asyncio.wait(servers,
|
||||
return_when=asyncio.FIRST_COMPLETED)
|
||||
except asyncio.CancelledError:
|
||||
# The launcher itself was cancelled: stop both listeners first
|
||||
# (graceful should_exit, hard cancel only as a last resort), await
|
||||
# their full exit, only then let the lifespan close (and re-raise).
|
||||
# No listener is ever left running without its state.
|
||||
for server in (http_server, https_server):
|
||||
server.should_exit = True
|
||||
for task in servers:
|
||||
with contextlib.suppress(asyncio.CancelledError, Exception):
|
||||
await asyncio.wait_for(asyncio.shield(task), timeout=5.0)
|
||||
for task in servers:
|
||||
task.cancel()
|
||||
with contextlib.suppress(asyncio.CancelledError, Exception):
|
||||
await task
|
||||
raise
|
||||
# Any listener ending stops the other FIRST; only after both listeners
|
||||
# have fully exited does the lifespan context above close the loop's
|
||||
# resources and the store — never the other way around.
|
||||
for server in (http_server, https_server):
|
||||
server.should_exit = True
|
||||
for task in pending:
|
||||
with contextlib.suppress(asyncio.CancelledError, Exception):
|
||||
await task
|
||||
for task in done:
|
||||
task.result() # surface the first listener's real error, after cleanup
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument("--http-port", type=int, default=8360)
|
||||
parser.add_argument("--https-port", type=int, default=8361)
|
||||
parser.add_argument("--cert", required=True)
|
||||
parser.add_argument("--key", required=True)
|
||||
parser.add_argument("--db", default=os.environ.get("CYBERGRIL_DB"))
|
||||
args = parser.parse_args()
|
||||
if args.db:
|
||||
os.environ["CYBERGRIL_DB"] = args.db
|
||||
asyncio.run(serve(args.http_port, args.https_port, args.cert, args.key))
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.exit(main())
|
||||
@@ -0,0 +1,18 @@
|
||||
# CyberGril 语音 worker 脱敏环境变量示例(HEL-877)
|
||||
#
|
||||
# 部署位置 /opt/voice-agent-cybergril/.env(权限 600,不进仓库)。
|
||||
# 复用 /opt/voice-agent/agent/venv(livekit-agents 1.8.8)与 .12 现有
|
||||
# LiveKit(7880)/FunASR(10095)/CosyVoice(9880);不新装任何依赖。
|
||||
|
||||
# 统一 CyberGril 实例(HTTP 8360 / HTTPS 8361 同进程双入口)
|
||||
CYBERGRIL_API_BASE=http://127.0.0.1:8360
|
||||
# 专属派发名(与 config/voice.yaml 的 agent_name 一致)
|
||||
CYBERGRIL_AGENT_NAME=cybergril-voice-agent
|
||||
# worker 注册 LiveKit 所需凭据(与通用 worker restart 脚本同源;只放占位符)
|
||||
LIVEKIT_URL=ws://127.0.0.1:7880
|
||||
LIVEKIT_API_KEY=<LIVEKIT_API_KEY_PLACEHOLDER>
|
||||
LIVEKIT_API_SECRET=<LIVEKIT_API_SECRET_PLACEHOLDER>
|
||||
# 专属健康端口(livekit-agents worker 内建 GET / 健康检查;8081 是通用 worker)
|
||||
CYBERGRIL_WORKER_HEALTH_PORT=8082
|
||||
# CyberGril 自己的音色状态文件(不读通用助手 voice_state.json)
|
||||
CYBERGRIL_VOICE_STATE=/opt/voice-agent-cybergril/voice_state_cybergril.json
|
||||
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env python3
|
||||
"""CyberGril R5 · WSS TLS bridge (PROPOSAL — 拟议材料,未在任何服务器执行).
|
||||
|
||||
背景(docs/rework/hel879/unified-review/r5-facts-20261027.md E2/E4):.12 的
|
||||
LiveKit 7880 是纯 HTTP/WS 且通用 worker/8090 演示都依赖它保持明文,不能改
|
||||
TLS;HTTPS 页面直连 ws:// 又是混合内容。本脚本在**新端口**终结 TLS 并把字节
|
||||
流透明转发给本机 7880,使浏览器可用 ``wss://192.168.200.12:<port>`` 接入
|
||||
LiveKit 信令,零新依赖(asyncio + ssl 标准库),不触碰既有服务。
|
||||
|
||||
- 监听(拟议):0.0.0.0:8363,证书 = 与 8361 同一张自签证书
|
||||
(SAN=IP:192.168.200.12,存 /opt/cybergril-voice-certs/,600)。
|
||||
- 上游:127.0.0.1:7880(仅回环,不暴露第二明文入口)。
|
||||
- voice.yaml:livekit_url 改 wss://192.168.200.12:8363;
|
||||
livekit_internal 保持 http://127.0.0.1:7880。
|
||||
- 实现为透明 TCP TLS 终结(不解析 WebSocket/HTTP),LiveKit 信令是 7880 上的
|
||||
HTTP/WebSocket,字节级转发即协议无关;WebRTC 媒体面(UDP/7881)不经本桥,
|
||||
由 WebRTC 自带 DTLS/SRTP 加密。
|
||||
- 每设备分别打开 https://192.168.200.12:8361 与 :8363,验证证书例外和实际
|
||||
连接;不推断例外缓存范围。禁止用 --ignore-certificate-errors 冒充验收。
|
||||
|
||||
部署(获批后)示例:
|
||||
python3 wss_bridge.example.py --listen 0.0.0.0:8363 \
|
||||
--upstream 127.0.0.1:7880 \
|
||||
--cert /opt/cybergril-voice-certs/cybergril-voice.pem \
|
||||
--key /opt/cybergril-voice-certs/cybergril-voice.key
|
||||
|
||||
回滚:停本进程即可(独立进程,不影响 LiveKit/通用 worker/8090)。
|
||||
|
||||
本地冒烟(零网络出站):见
|
||||
docs/rework/hel879/unified-review/r5-facts-20261027.md 与
|
||||
docs/rework/hel879/unified-review/wss-bridge-smoke.log(一次性本地证书 +
|
||||
dummy 上游回环验证字节穿透与 TLS 握手)。
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import asyncio
|
||||
import contextlib
|
||||
import ssl
|
||||
import sys
|
||||
|
||||
|
||||
async def _pipe(reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None:
|
||||
try:
|
||||
while True:
|
||||
data = await reader.read(65536)
|
||||
if not data:
|
||||
break
|
||||
writer.write(data)
|
||||
await writer.drain()
|
||||
except (ConnectionError, asyncio.CancelledError, ssl.SSLError):
|
||||
pass
|
||||
finally:
|
||||
with contextlib.suppress(Exception):
|
||||
writer.close()
|
||||
|
||||
|
||||
async def _handle(
|
||||
downstream: tuple[asyncio.StreamReader, asyncio.StreamWriter],
|
||||
upstream_host: str,
|
||||
upstream_port: int,
|
||||
) -> None:
|
||||
down_reader, down_writer = downstream
|
||||
try:
|
||||
up_reader, up_writer = await asyncio.open_connection(upstream_host, upstream_port)
|
||||
except (ConnectionError, OSError):
|
||||
down_writer.close()
|
||||
return
|
||||
await asyncio.gather(
|
||||
_pipe(down_reader, up_writer),
|
||||
_pipe(up_reader, down_writer),
|
||||
return_exceptions=True,
|
||||
)
|
||||
|
||||
|
||||
async def main(argv: list[str] | None = None) -> int:
|
||||
parser = argparse.ArgumentParser(description="TLS->plain TCP bridge (CyberGril R5 WSS proposal)")
|
||||
parser.add_argument("--listen", default="0.0.0.0:8363", help="host:port to terminate TLS on")
|
||||
parser.add_argument("--upstream", default="127.0.0.1:7880", help="plain upstream host:port")
|
||||
parser.add_argument("--cert", required=True, help="TLS certificate PEM path")
|
||||
parser.add_argument("--key", required=True, help="TLS private key path")
|
||||
args = parser.parse_args(argv)
|
||||
|
||||
listen_host, _, listen_port = args.listen.rpartition(":")
|
||||
up_host, _, up_port = args.upstream.rpartition(":")
|
||||
if not listen_host or not up_host:
|
||||
parser.error("listen/upstream must be host:port")
|
||||
|
||||
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER)
|
||||
ctx.load_cert_chain(args.cert, args.key)
|
||||
|
||||
async def handler(reader: asyncio.StreamReader, writer: asyncio.StreamWriter) -> None:
|
||||
await _handle((reader, writer), up_host, int(up_port))
|
||||
|
||||
server = await asyncio.start_server(
|
||||
handler, listen_host or "0.0.0.0", int(listen_port), ssl=ctx
|
||||
)
|
||||
addrs = ", ".join(str(s.getsockname()) for s in server.sockets or [])
|
||||
print(f"wss-bridge(PROPOSAL) tls {addrs} -> {up_host}:{up_port}", file=sys.stderr)
|
||||
async with server:
|
||||
await server.serve_forever()
|
||||
return 0
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(asyncio.run(main()))
|
||||
@@ -0,0 +1,73 @@
|
||||
{
|
||||
"base": "bf234570c0b6595a72f8dbc79e42c63685e08e01",
|
||||
"patch_sha256": "02a7b3d2c03aee79c9fc7c8a470c7053cd7b8aa410699ec51b255c333acdeda4",
|
||||
"source_zip_sha256": "4596f2cc03210074be1fc9fe23dcdd607f5d240b16f142b67986c1886ce6e9be",
|
||||
"files": [
|
||||
{
|
||||
"path": "docs/requirements/handoff-HEL-878.json",
|
||||
"sha256": "258cf2935f5aafc20cd7a80a9550ae062024849ff39c078068f371692bbaa516",
|
||||
"bytes": 9439
|
||||
},
|
||||
{
|
||||
"path": "web/README.md",
|
||||
"sha256": "f596492a443e7ae9972496a40db2f40c79f8667d4552628afa4718efbd29c726",
|
||||
"bytes": 3113
|
||||
},
|
||||
{
|
||||
"path": "web/VENDOR.md",
|
||||
"sha256": "e11c139b5c7a6f86264439b03997bd89c79e40c994ac1db57f31717e83b660b6",
|
||||
"bytes": 893
|
||||
},
|
||||
{
|
||||
"path": "web/public/vendor/livekit-client-2.22.4.umd.min.js",
|
||||
"sha256": "040db4c0db72e7f7599cd0e06b0f58f95e0082a395cdde410ca26224a79a0626",
|
||||
"bytes": 598796
|
||||
},
|
||||
{
|
||||
"path": "web/src/app/RealApp.tsx",
|
||||
"sha256": "8afb63b8a6b196e29ced1a8bcef541f1f80a10811f1dc0f965631a9f0c201f5e",
|
||||
"bytes": 14382
|
||||
},
|
||||
{
|
||||
"path": "web/src/chat/ChatPanel.tsx",
|
||||
"sha256": "419c2f4243d7a147ea8ebcf377d74c97dc558049a3bf76dee39bba0746d2c9e6",
|
||||
"bytes": 34936
|
||||
},
|
||||
{
|
||||
"path": "web/src/styles/components.css",
|
||||
"sha256": "f93b875f6918d402aaaefeffdc52fdd908328fb8ac70766704e528c6a8bc154d",
|
||||
"bytes": 89243
|
||||
},
|
||||
{
|
||||
"path": "web/src/voice/livekit.ts",
|
||||
"sha256": "c42475d37f7eef7abe0903b66656aedc5379bc9de3dcba11c1b88450a470ab04",
|
||||
"bytes": 6859
|
||||
},
|
||||
{
|
||||
"path": "web/src/voice/session.ts",
|
||||
"sha256": "128123ab75e788699150321ca1341081450c34b09918b0b825c542dbc60b6e07",
|
||||
"bytes": 18058
|
||||
},
|
||||
{
|
||||
"path": "web/tests/fake-livekit.js",
|
||||
"sha256": "d16e794308073e967566f3ebda16e72d0f5eb0132b657338baa6a29115b02508",
|
||||
"bytes": 4177
|
||||
},
|
||||
{
|
||||
"path": "web/tests/hel878_mock.mjs",
|
||||
"sha256": "d7c9d79308979f1f3cd7172f56f52b4cfb35de1fcbae2876fa7d66ea4e2c3071",
|
||||
"bytes": 8855
|
||||
},
|
||||
{
|
||||
"path": "web/tests/hel878_shots.mjs",
|
||||
"sha256": "ad664b26b66990e59ca118b0afe1e6dfea8a64351bb9bbb7a666f332b2f15760",
|
||||
"bytes": 22874
|
||||
},
|
||||
{
|
||||
"path": "web/tests/voice.test.ts",
|
||||
"sha256": "f6bc899b3202465ec68b276ed21ccbbc5ba6e7edda014e2d7ea3ff63e5683a73",
|
||||
"bytes": 20829
|
||||
}
|
||||
],
|
||||
"unchanged_archive_files_match_base": true
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
HEL-878 源码保全与补查(总管,2026-10-27 北京时间)
|
||||
|
||||
原作者提交评论:01a1797c-188d-79df-9be1-df6bd47effc6。读取需求 v1.11/60项;前端基点 bf234570c0b6595a72f8dbc79e42c63685e08e01,后台契约 aba2aeb,实际总装基点 04eff611e7d85e539d43717711172441420ac853,main 3a986726d8593e0ed2274f79db6cc5d807d2ebf0。
|
||||
|
||||
13 个改动文件逐字节匹配作者 MANIFEST;补丁 SHA-256 匹配,git apply --reverse --check 通过;源码包其余文件与 bf234570 内容一致(仅允许未改文件 CRLF/LF 差异),包内 MANIFEST 与单独附件一致。原样提交 b95ce798b4a9455d941d247a46865b3ac202bf2c,不改作者业务代码或视觉。
|
||||
|
||||
补齐前端分支缺少的历史用户原话文件 comment-evidence-full-experience-20261026.json 及 source-manifest,逐字节来自总装 04eff611;无需求变更。Python 原版检查对 origin/main、origin/hel-870-assembly、origin/agent/2/6a08a4c18f23 各带/不带 handoff-HEL-878.json 共6次通过。
|
||||
|
||||
使用既有 node_modules(未安装下载)复跑 typecheck、lint、81项单测、build 全通过;lint 0错/1条既有警告。作者45项浏览器检查本轮未重跑,仍为作者证据。真实语音、真实麦克风、WebRTC、ASR/TTS/LLM请求均未执行;未部署、未合并、未改现有服务或绑定。
|
||||
|
||||
独立补查发现必须返修的问题:
|
||||
|
||||
1. 第一次会话正常开启;模拟掉线,服务端 DELETE s1 延迟返回。
|
||||
2. 用户立即开启第二次会话,worker已加入,界面 listening,controller.active=true。
|
||||
3. 放行第一次的 DELETE(含 settle 补偿请求)。旧 fail() 在 await teardown(live) 之后继续写 OFF,没有重新核对代次,覆盖新会话的界面。
|
||||
4. 实测:controller.active=true,但最后 onView.phase=off。旧失败提示也会覆盖新会话,界面与麦克风会话状态不一致。
|
||||
|
||||
定位 web/src/voice/session.ts 的 start() 内 fail()。附件 review878_late_cleanup.test.ts 为独立负例,放到 web/tests/ 后用 ./node_modules/.bin/vitest run tests/review878_late_cleanup.test.ts 可复现;本轮实际执行失败:Expected listening / Received off,原始日志见 review878-race.log。这里只做有限复现,未代替原作者修改;交原作者修复异步清理后的状态提交边界并补有意义回归。
|
||||
|
||||
关联 CG-010/018、VIS-013、UX-005/006、GOV-001–006、DEL-001。原81项通过不涵盖这个负例,不能称离线验收通过。修正后交 HEL-879 统一审核;CG-011语音主动开口仍为空操作、增量字幕仍缺、远端断网清理/租约与API重启实情、真实SDK回调与播放回执、真机三轮/打断/停止/HTTPS均继续承接,不因协议现状或mock通过降低完整要求。R6/R7继续主卡HEL-797承接。
|
||||
@@ -0,0 +1,171 @@
|
||||
# HEL-895 · 真实全链一次批准执行包(A/B/C 合并核定稿;仍全部待授权,默认 0 不变)
|
||||
|
||||
> **HEL-896 分账修订(2026-10-27)**:总管独立复审证实,若按本文件 §1 原表把 A 的
|
||||
> `total_requests=55` 写进与 B/C 共用的产品库,B 的 `mem0_extract` 与 C 的
|
||||
> `dialogue_main` 在 A 用满 55 次后都被 `budget_total_requests_exhausted:55/55` 挡死
|
||||
> (复现 `tools/verify_budget_split_hel896.py` S0;账表也无阶段/授权来源字段)。
|
||||
> **执行口径改为 §6:A 落在独立团队测试实例自己的库,B/C 落在全新用户实例的库,
|
||||
> 用户实例永不配置一次性总量。** §1–§5 与本修订冲突处以 §6 为准;四道闸叠加、
|
||||
> 保守入账、碰顶停机等语义不变。
|
||||
|
||||
本文件把 `docs/budget-plan-hel874.md` 的 A/B/C 三表收拢成**一次可批准的具体执行包**:
|
||||
每一步的请求/嵌入/失败-取消-重试上限、累计与日顶的叠加口径、一次性团队检查与用户
|
||||
日常使用的分账、碰顶停机语义与留证方式。技术核对基于本卡实际代码与配置
|
||||
(`src/cybergril/life/model.py` 的 `PersistentBudget`、`src/cybergril/think/budget.py`、
|
||||
`config/models.yaml`、`config/semantic.example.yaml`、299 pytest 含
|
||||
`tests/test_hard_gates_hel882.py`)。
|
||||
|
||||
**批准状态:三部分均未批准。随包 `models.yaml` 全部上限为 0(未批准即发送前拒绝),
|
||||
`semantic.example.yaml` 缺省全 0。本卡零真实调用、零真实嵌入、零权威账写入。**
|
||||
旧账 39/60(真实请求)与 498/500(嵌入,冻结 2 条)及 HEL-835 闸原样保全,
|
||||
不挪用、不重置、不并入。真实数值只有白栖知批准后由总管写入。
|
||||
|
||||
## 1. 批准项(一个包,三个独立账)
|
||||
|
||||
| 部分 | 用途 | 硬顶(批准后由总管写入) | 账本(HEL-896 修订:见 §6 实例分账) |
|
||||
| --- | --- | --- | --- |
|
||||
| A · 一次性团队整体检查 | 8360 隔离实例按体验链 1–7 全链走一遍(stub 语义,零嵌入) | 总量 55 次请求 / 500,000 tokens / 0 嵌入(`budget.total_requests`/`total_tokens`,跨日累计)——**只写团队实例自己的库** | 团队实例库的 `budget_total`/`request_usage`/`token_usage` |
|
||||
| B · 首周语义激活 | `CYBERGRIL_SEMANTIC=mem0` 真实激活观察 | 提取 LLM ≤60 次(`llm_cap`);嵌入 ≤180 条新批 → 按算式写 `embed_cap=680`、`embed_reserve=2`(权威账已用 498/原批 500) | `llm_ops`(新表)/`embed_ops`(权威账续账,`authority` 冻结前缀必填) |
|
||||
| C · 用户日常使用 | 体验地址交付后每日 | dialogue ≤60/日、life ≤8/日、background ≤40/日、semantic ≤40/日(`daily_requests`);嵌入 ≤60 条/日(`embed_daily`);tokens ≤2,000,000/日(`daily_tokens`,全类别共池) | 用户实例库的持久表 + 日顶列(**不配置一次性总量**) |
|
||||
|
||||
【HEL-896 勘误】原文「A 当天同时受 C 类日顶约束」按共用产品账本表述,会把 A 的消费
|
||||
算进用户的日账并让 A 的 55 总量挡住 B/C;修订后 A 在自己的实例与账本内受**同数值**的
|
||||
类别日顶约束(§6 S1 验证:life 日顶 8/8 先于总量拒绝、semantic 余量内由总量拒绝——
|
||||
叠加取最紧),与用户实例日账互不相干。B 期间的对话/生活/判定请求并入 C 日账,
|
||||
不占 B 的 60 次。三部分独立授权来源保持:A 需总管新批(产品环境网关用量不属于
|
||||
HEL-857 的 60 次实验授权);B/C 需白栖知明确批准。
|
||||
|
||||
## 2. 叠加口径(逐笔发送前原子预占;总管核定值写入后自动生效)
|
||||
|
||||
一次真实 provider 发送(创建/对话/生活/gist/判定/成长/主动措辞/Mem0 内部提取)
|
||||
在 `PersistentBudget.acquire` 同时过四道闸,任一到顶即 `BudgetStop` 拒绝,**不降档续调**:
|
||||
|
||||
1. 类别日顶(该调用所属 `daily_requests` 类别:dialogue/life/background/semantic);
|
||||
2. 日 token 池(`daily_tokens`,全类别共池;70% 警告、95% 非关键场景 structured 预检先停);
|
||||
3. A 部分一次性总量(`total_requests`/`total_tokens`,跨日累计,重启不归零);
|
||||
4. B 部分类别账:Mem0 内部提取 LLM 另过 `llm_cap` 累计 + `llm_daily`;嵌入过
|
||||
`embed_cap` 累计(含冻结 `embed_reserve`)+ `embed_daily`。
|
||||
|
||||
**交叉核对结论(本卡逐项核过代码与测试):**
|
||||
- **交叉(有意叠加,非重复计费)**:A 的每次请求同时计入 A 总量与当天类别日顶;
|
||||
B 的每次提取 LLM 同时计入 `llm_ops` 累计与 semantic 日顶 + 日 token 池。两处计数
|
||||
用途不同(一个限一次性总量/首周观察,一个限每天),不会互相退款或放宽。
|
||||
- **不重复**:嵌入只记 `embed_ops`(条数),不进请求计数;提取 LLM 只在
|
||||
`llm_ops`+统一请求闸各记一次;主对话与语义层各自独立闸(`tests/` 双实例同库复现)。
|
||||
- **不漏记**:四个请求类别(dialogue/life/background/semantic)+ 嵌入 + 全池 token
|
||||
已覆盖全部产品出站点;SDK 隐藏重试已禁用(`max_retries=0`),每次实际发送都过闸。
|
||||
|
||||
## 3. 失败、取消与重试(保守入账,不退款)
|
||||
|
||||
- 发送前预占(请求次数 + 保守 token 估算:输入字符 1:1 + 声明 max_tokens 全额);
|
||||
provider 返回真实 usage 按实际修正(多补少退)。
|
||||
- 未知 usage/断流/失败/取消保守保留全部预占;已发送的成本不当未发生。唯一释放
|
||||
路径是可证明未连接(`httpx.ConnectError` 级)的显式 `release()`。
|
||||
- 真实错误重试 ≤3 次/批;预算拒绝不耗重试次数——作业回 `queued`
|
||||
(reason=`semantic_*_budget_*`),总管调 cap 后同批续跑,已完成行不重发。
|
||||
- 嵌入:单条失败释放;批次中途失败整批保守落账。
|
||||
|
||||
## 4. 碰顶停机语义与留证
|
||||
|
||||
- **全部硬闸在发送前**拒绝(`budget_*_exhausted` / `semantic_*_budget_*`),拒绝如实
|
||||
记录,不补发、不换渠道。
|
||||
- 语义层到顶只停语义(检索回落词面 FTS,主对话不中断);日 token 到顶停当日全部
|
||||
真实调用;A 总量到顶即团队检查收尾。
|
||||
- 留证:`budget_total`/`request_usage`/`token_usage`/`embed_ops`/`llm_ops` 表 +
|
||||
服务日志 + 隔离实例数据目录(【HEL-896 勘误】在线库直接复制主 `.db` 会丢 WAL 中
|
||||
已提交行——归档一律停服务+checkpoint 或 SQLite backup API 一致性快照,见
|
||||
`tools/release_snapshot_hel896.py` 与 `deploy/hel895-release-candidate.md` §5);
|
||||
碰顶当时的拒绝 reason 与计数快照截图/导出一并归档到交付评论。
|
||||
|
||||
## 5. 本包默认状态(本卡随包可执行)
|
||||
|
||||
`config/models.yaml`:`daily_tokens: 2000000`(结构性默认值,非授权)、
|
||||
`daily_requests.*` 全 0、A 部分总量两行保持注释(待批);`config/semantic.example.yaml`
|
||||
全部 cap/daily 为 0、`authority` 必填结构就位。**未写入批准值前,任何创建/对话/
|
||||
生活/gist/判定/成长/主动措辞/提取调用都在发送前被硬闸拒绝(`budget_*_exhausted`),
|
||||
这是设计行为;已由 `tools/check_release_offline_hel882.py` R3 与 299 pytest 复现。**
|
||||
|
||||
## 6. HEL-896 可执行分账与阶段切换(独立团队测试实例 + 全新用户实例)
|
||||
|
||||
本节把 A/B/C 落成可直接执行的实例/账本拆分;全部语义由
|
||||
`tools/verify_budget_split_hel896.py` 在临时库+替身上验证(零 provider、零真实 cap
|
||||
变更,证据 `docs/rework/hel896/budget-split/budget-split.json`)。不新造预算引擎,
|
||||
不改表结构:`budget_total/request_usage/token_usage` 无阶段字段这一事实,
|
||||
正是用实例隔离代替字段拆分的理由。
|
||||
|
||||
### 6.1 实例与账本拆分
|
||||
|
||||
| | 团队测试实例(A) | 用户实例(B/C) |
|
||||
| --- | --- | --- |
|
||||
| 形态 | 8360 端口隔离 systemd 单元(`deploy/cybergril-hel874-8360.service.example` 模式),独立数据目录 | 发布候选部署的全新实例,**全新空库**(用户自己创建唯一真实档案) |
|
||||
| `models.yaml` | `total_requests: 55`、`total_tokens: 500000` + 当日类别日顶(同 C 表数值)+ `daily_tokens` | **永不配置 `total_requests`/`total_tokens`**(保持注释/缺省);只写 C 表日顶;`budget_total` 行仅作流量记录,无总量闸(S3 验证) |
|
||||
| 语义层 | `CYBERGRIL_SEMANTIC=stub`(零嵌入、零真实 Mem0) | B 批准后 `=mem0`;`embed_cap/llm_cap/embed_daily/llm_daily` 只在白栖知批准后由总管写入 `config/semantic.yaml`(含 `authority` 冻结前缀) |
|
||||
| 账本 | 自己的 SQLite(`budget_total` 等);封账后归档留存 | 自己的 SQLite 日账 + 权威 `embed_ops` 续账(498/500 + 冻结 2 条原样) |
|
||||
| 授权来源 | 总管新批(产品环境网关用量,不属于 HEL-857 60 次实验授权) | B/C 均需白栖知明确批准(一次批准包 = 本文件) |
|
||||
|
||||
误配守门:用户实例若误写 `total_requests`,A 型堵死会立刻复现(S4)——发布卡
|
||||
部署检查单必须逐项核对用户实例 `models.yaml` 无一次性总量两行、团队实例配置只存在
|
||||
于 8360 数据目录。
|
||||
|
||||
### 6.2 A 的执行与封账
|
||||
|
||||
1. 总管批准后写入团队实例 `models.yaml`(仅该实例),按
|
||||
`docs/budget-plan-hel874.md` §1 体验链 1–7 逐步执行:创建/诠释/习惯 4、对话 16、
|
||||
生活 8、判定/成长/gist 20、主动措辞 3,其余额度备用至 55;每步在四道闸下原子
|
||||
预占(类别日顶→日 token 池→一次性总量;S1 验证叠加取最紧)。
|
||||
2. **A 结束即封账**,两种到达方式都有可执行动作(HEL-879 收口):额度用满时
|
||||
`budget_total_requests_exhausted:55/55` 如实拒绝、不补发;**体验链提前走完
|
||||
(如 51/55)时运行 `tools/seal_budget_hel879.py --db <团队实例库>` 显式封账**
|
||||
——真实用量 51 原样写入并保留(不伪造 55、不清零),此后该库任何类别任何
|
||||
余量的 `acquire` 都拒绝 `budget_sealed:51/55`,跨重启、跨 backup API 归档/
|
||||
快照恢复同样拒绝(S6 负例:51/55 提前收尾、误重启、归档恢复均拒绝;重复
|
||||
seal 幂等不覆盖原标记;无解除封账代码路径)。封账动作顺序:`systemctl stop`
|
||||
8360 实例 → `seal_budget_hel879.py` → `tools/release_snapshot_hel896.py`
|
||||
一致性快照(封账标记随库一同归档)→ 归档(数据目录 + 哈希清单)交交付评论。
|
||||
`budget_total` 永不手工清零。
|
||||
3. **旧测试数据不会转成用户伴侣**:测试档案、聊天、生活数据只存在于团队实例库与
|
||||
归档;用户实例是全新空库,由用户自己创建档案;产品无任何「测试库导入用户库」
|
||||
路径,发布卡明令禁止把 8360 数据目录复制/合并进用户实例数据目录。
|
||||
4. 后续任何团队复检 = **新批准 + 全新隔离实例/新库**,绝不续在用户账上,也
|
||||
**绝不在已封账的 8360 库上抬 `total_requests` 重开**(HEL-879 返修勘误:本节
|
||||
旧版括注「或在 8360 实例上以新批准抬 total_requests」与「无解除封账路径」
|
||||
自相矛盾——封账标记随库持久,抬 cap 不能也不得绕过它;该括注废除)。旧
|
||||
8360 库及其封账标记原样归档留存,作为真实用量的证据链。
|
||||
|
||||
### 6.3 B/C 的开始与日常
|
||||
|
||||
1. **B 开始的配置与授权**:白栖知批准后,总管把 `llm_cap: 60`、按算式
|
||||
`embed_cap: 680`、`embed_reserve: 2`、`llm_daily/embed_daily`(C 表值)与
|
||||
`authority`(权威账前缀逐行摘要 + `min_used: 498`)写入用户实例
|
||||
`config/semantic.yaml`,`CYBERGRIL_SEMANTIC=mem0` 生效;缺/错 authority 在构造前
|
||||
fail-closed(HEL-885 既有验证,不在本卡重复)。
|
||||
2. **真实 Mem0 冒烟与 B 首周的关系**:A 的 stub 检查证明产品链路零语义也能走通;
|
||||
B 激活当天先做**真实 Mem0 冒烟**(数条 add/search/原话回读),其 LLM/嵌入消费
|
||||
全部计入 B 的 `llm_ops`/`embed_ops`(即 60/180 的一部分,不另设隐藏额度),冒烟
|
||||
通过即进入首周观察;B 期间用户对话/生活/判定照走 C 日账,与 B 的累计账并行不占额。
|
||||
3. **B 到顶的停/续语义**:任一 cap 到顶 → 作业批回 `queued`
|
||||
(reason=`semantic_*_budget_*`)不丢行不耗重试,语义层停(检索回落词面 FTS,
|
||||
主对话不中断);**续跑唯一路径 = 新批准按算式抬 cap**(`embed_cap = 原上限 +
|
||||
新增量`),总管写入后同批续跑,已完成行不重发。无新批准则语义层停在原地,
|
||||
不自动翻页、不挪用 C 额度、不动冻结余额。
|
||||
4. **首周结束的停/续语义**:7 天观察期满,总管导出 `llm_ops`/`embed_ops`/日账实际
|
||||
用量与质量观察报告交白栖知;未获新批准,B 保持当时 cap(用尽即停语义),
|
||||
C 日常照常;获批续期则按新算式写新 cap。B 与 C 无任何自动转换或继承。
|
||||
5. **全局累计与日顶的叠加**(仅用户实例内部):每笔真实发送四道闸原子预占、取最紧
|
||||
(类别日顶 → 日 token 池 → B 的累计 cap×2 → embed/llm 日顶);A 的总量闸不在
|
||||
用户实例存在(S3/S4 验证两侧)。39/60(HEL-857 真实请求旧账)与 498/500、冻结
|
||||
2 条、HEL-835 闸是历史授权事实记录,不属于任何实例配置,本轮零改动(S5)。
|
||||
|
||||
### 6.4 一次负责的有限推荐(供总管一次性向白栖知申请;默认值不变)
|
||||
|
||||
- **A(总管权限内新批)**:55 次请求 / 500,000 tokens / 0 嵌入,仅 8360 团队实例,
|
||||
体验链走完即封账归档。
|
||||
- **B(白栖知批准)**:提取 LLM 累计 60 次;嵌入新增 180 条(`embed_cap=680`、
|
||||
`embed_reserve=2` 续权威账);`llm_daily=40`、`embed_daily=60`;首周观察,期满
|
||||
凭实际用量报告决定停/续。
|
||||
- **C(白栖知批准)**:dialogue 60/日、life 8/日、background 40/日、semantic 40/日;
|
||||
嵌入 60 条/日;tokens 2,000,000/日。
|
||||
- 推荐理由:A 按体验链实测上界+备用;B 按 HEL-874 实测单次开销(add 1 LLM + 2–3
|
||||
嵌入)对 60 次提取 ≈ 最多 180 条嵌入;C 按生活槽 4/天与 60 轮对话日常上界。
|
||||
真实失败/取消保守入账不退款、重试 ≤3 次/批(§3)不额外放大。
|
||||
- 三笔互相独立、逐笔硬闸、默认 0;未批准部分保持 fail-closed,不因其余获批自动放开。
|
||||
@@ -0,0 +1,140 @@
|
||||
# HEL-874/882 · 真实整体检查执行表(有确定上限,交总管核定)
|
||||
|
||||
本表取代 runbook-hel870 §6 的估算口径:**原「约 20–30 次请求 / 100–200 条嵌入」
|
||||
只是估算,不构成任何批准额度。**HEL-874 本卡零真实模型调用、零出站;
|
||||
**HEL-882 勘正**:HEL-874 的真实 SDK 验证脚本当时未替换 fastembed 边界,
|
||||
运行过真实本地嵌入推理(可证下限 12 条,详见 docs/rework/hel874/erratum-hel882.json),
|
||||
自 HEL-882 起验证边界为确定性 512 维替身 + 禁非回环,零真实嵌入。
|
||||
|
||||
三部分各自独立账本与授权来源;超出既有授权的部分由总管向白栖知申请,
|
||||
批准前对应硬闸保持 `cap=0`(fail-closed,任何真实工作前拒绝)。
|
||||
HEL-857 系列冻结余额(真实请求 39/60、嵌入 498/500、HEL-835 闸)不挪用、
|
||||
不清零、不并入本表任何一部分;**换新账本文件绕过冻结会被
|
||||
`verify_ledger_authority` 拒绝(HEL-882)**。
|
||||
|
||||
## 0. 实测单次开销与入账口径(真实固定 SDK 验证得出,docs/rework/hel874/)
|
||||
|
||||
| 操作 | LLM 请求 | 嵌入条数 | 说明 |
|
||||
| --- | --- | --- | --- |
|
||||
| Mem0 单行 add(infer) | 1 | 2–3 | phase1 查询嵌入 1 + phase3 提取批嵌入 N + phase7 实体 upsert 0..N |
|
||||
| Mem0 search | 0 | 1 | 问答每轮 1 条查询嵌入 |
|
||||
| 失败/取消(HEL-882 口径) | 见下 | 见下 | **保守入账,不退款** |
|
||||
| 重试上限 | 每批 ≤3 次 | 同上×3 | 预算拒绝不耗次数(重排队等预算);真实错误 3 次后 failed |
|
||||
|
||||
**入账口径(HEL-882 修正,总管独立复现驱动):**
|
||||
|
||||
- **发送前预占**:所有真实 provider 出口(创建/对话/生活/gist/判定/成长/主动
|
||||
措辞及 Mem0 内部提取 LLM)在发送前经 `PersistentBudget.acquire` 原子预占
|
||||
「请求次数(类别日顶 + 一次性总量)+ 日 token(保守估算)」,任一到顶即
|
||||
`BudgetStop` 拒绝——**不再降档继续调用**;持久落库(`token_usage`/
|
||||
`request_usage`/`budget_total`),重启不归零、并发不越顶。
|
||||
- **token 保守性**:估算 = 输入字符数 1:1 + 声明的 max_tokens 全额(中英文
|
||||
两个方向都高估);provider 返回真实 usage 按实际修正(多补少退),未知
|
||||
usage/断流/失败/取消保守保留全部预占——已发送的成本不当未发生。
|
||||
- **SDK 隐藏重试已禁用**:固定安装内 OpenAI client `max_retries=0`,每次实际
|
||||
发送过闸计数;被网关应答过的失败(含 5xx)照实入账,只有可证明未连接
|
||||
(httpx.ConnectError)才释放预占。
|
||||
- **嵌入批次保守性**:单条嵌入失败(未产出向量)释放;批次中途失败无法证明
|
||||
哪些已推理,整批保守落账。
|
||||
- **Mem0 内部 LLM**:独立 `llm_ops` 累计账(B)+ `llm_daily` 日顶(C)+ 统一
|
||||
请求闸(`semantic` 类别 + 日 token 池,发送前预占)。
|
||||
- **未知预占不退款(HEL-885)**:`reserve:` 预占行不再按一小时超时清除——
|
||||
已发送后崩溃未 settle 的消费事实必须保留;唯一删除路径是可证明未发送的
|
||||
显式 `release()`(如 httpx.ConnectError 级未连接)。作业租约过期不是
|
||||
「未发生」的证明。跨日结算/释放一律按预占凭据的 `hold.day` 记回原日,
|
||||
不冲新一天、不产生负用量(`token_usage`/`request_usage` 同口径)。
|
||||
|
||||
## 1. A 部分 · 一次性团队整体检查(隔离空库,非用户档案)
|
||||
|
||||
用途:统一候选在 8360 隔离实例上按体验链路清单 1–7 全链走一遍(stub 语义,
|
||||
不激活 Mem0),验证创建→对话→生活→情绪/关系→主动联系→重开同步与隐私负例。
|
||||
|
||||
| 项 | 次数上限(硬顶) |
|
||||
| --- | --- |
|
||||
| 创建 + 自主诠释 + 初始习惯 | 4 次请求 |
|
||||
| 对话(含多轮、中断重试) | 12 轮 ≤ 16 次请求 |
|
||||
| 生活槽(4 槽)+ 打断/恢复 | ≤ 8 次请求 |
|
||||
| 分享判定 / 成长 / gist | ≤ 20 次请求(每完成轮 2 条 gist × 最多 8 轮 + 判定/成长若干) |
|
||||
| 主动联系措辞 | ≤ 3 次请求 |
|
||||
| **合计硬顶** | **55 次请求 / 500,000 tokens / 0 嵌入** |
|
||||
|
||||
- 硬闸(HEL-882 起为真实硬闸):`config/models.yaml` `budget.total_requests=55`
|
||||
`budget.total_tokens=500000`(跨日累计,落 `budget_total` 表)+ 各类别
|
||||
`daily_requests`(A 检查当天也受日顶约束,按 C 表或总管核定值)+ `daily_tokens`。
|
||||
任一到顶在发送前拒绝(`budget_*_exhausted`),拒绝如实留证不补发。
|
||||
- 授权来源:**需总管新批**(.11:8731 网关在产品环境的用量不属于 HEL-857 的
|
||||
60 次实验授权)。
|
||||
|
||||
## 2. B 部分 · 首周后台/语义激活(需白栖知批准后执行)
|
||||
|
||||
用途:`CYBERGRIL_SEMANTIC=mem0` 真实激活,独立新账(`embed_ops` 续账 +
|
||||
`llm_ops` 新表),观察提取/检索/原话回读在真实使用中的质量。
|
||||
|
||||
| 项 | 上限(硬顶) |
|
||||
| --- | --- |
|
||||
| Mem0 提取 LLM(随公开轮 add) | ≤ 60 次(`llm_cap`) |
|
||||
| 嵌入(提取批 + 实体 + 查询) | ≤ 180 条(`embed_cap`) |
|
||||
| 对话/生活/判定等其余 | 并入 C 部分日账 |
|
||||
|
||||
**累计 cap / 保留量算式(HEL-885,写入 config 前照此换算,禁止把增量直接填进累计上限):**
|
||||
|
||||
```
|
||||
权威账现状 :已用 498 条,原批上限 500,冻结不动余额 2 条
|
||||
新批增量 :白栖知批准的 B 部分嵌入条数(示例 180)
|
||||
embed_cap = 500 + 180 = 680 # 原批上限 + 新批增量(≠ 180)
|
||||
embed_reserve= 2 # 原冻结余额继续保留,不得消耗
|
||||
可用余量 = 680 − 498 − 2 = 180
|
||||
authority = {prefix_rows: <权威账前N行>, prefix_sha256: <逐行摘要>,
|
||||
min_used: 498} # HEL-885 起任一 cap>0 时必填,缺/空/错即拒绝构造
|
||||
```
|
||||
|
||||
错误示例:对已用 498 的账把 `embed_cap` 填成 180(等于瞬间耗尽并掩盖历史用量);
|
||||
以任何方式消耗旧冻结 2 条(`min_used: 498` 保证拒绝)。`authority` 块缺省或
|
||||
整段注释时,mem0 模式在构造前 fail-closed(`ledger_authority_required`),
|
||||
不再是可以跳过的可选项。
|
||||
|
||||
- 硬闸:`embed_cap`/`llm_cap`(累计)+ `embed_daily`/`llm_daily`(日顶)写入
|
||||
config/semantic.yaml(默认全 0=拒绝);预占-落账事务制保证并发不越 cap;
|
||||
`embed_reserve` 预留复测余量;`authority` 冻结前缀块拒绝新文件绕过 498/500。
|
||||
- 碰上限即停:作业批回到 `queued`(reason=`semantic_*_budget_*`),**不耗重试
|
||||
次数、不丢行**——总管调 cap 后同一批续跑,已完成的行不再重发(向量库逐行
|
||||
锚点 + `sem_row_done` 逐行完成记录,HEL-885:每个向量只证明自己那一行,
|
||||
空提取行同样有完成证明);检索返回空块、对话回落词面 FTS,主对话不中断;
|
||||
不自动翻页。
|
||||
- SDK 吞错已堵住:中途嵌入被预算挡住时 mem0 返回空列表,产品现在识别为预算
|
||||
拒绝并重排队(不再误写 done/[] 造成永久漏整理)。
|
||||
- 授权来源:**需白栖知明确批准**(提高嵌入上限或另批独立账;现有 498/500
|
||||
余额 2 条不够任何真实激活,属 HEL-835 未解闸范围)。
|
||||
|
||||
## 3. C 部分 · 用户日常使用(体验地址交付后)
|
||||
|
||||
| 项 | 日上限(硬顶,建议值交核定) |
|
||||
| --- | --- |
|
||||
| 主对话 + 主动措辞 + 危机 | ≤ 60 次/日(类别 `dialogue`) |
|
||||
| 生活事件生成(4 槽/天) | ≤ 8 次/日(类别 `life`) |
|
||||
| gist/判定/成长(含创建诠释) | ≤ 40 次/日(类别 `background`) |
|
||||
| Mem0 提取 LLM | ≤ 40 次/日(类别 `semantic`,`llm_daily`) |
|
||||
| 嵌入(全部) | ≤ 60 条/日(`embed_daily`) |
|
||||
| tokens | 2,000,000/日(`daily_tokens`) |
|
||||
|
||||
- 硬闸(HEL-882):上表全部落 `daily_requests`/`embed_daily`/`llm_daily`/
|
||||
`daily_tokens`,发送前原子预占、到顶拒绝、重启不归零;`daily_tokens` 到
|
||||
95% 非关键场景仍先降档/停(structured 预检),**到顶一律硬停不降档续调**;
|
||||
嵌入/提取到顶只停语义层,主对话可继续(其类别独立计账)。
|
||||
- 授权来源:**需白栖知批准日预算后**才能交付体验地址;首周日用量按本表
|
||||
B 部分上限受控观察,超限如实记录不补发。
|
||||
|
||||
## 4. 本卡已核实的闸门事实(代码级,测试可复现)
|
||||
|
||||
1. `embed_cap=0` / `llm_cap=0` / `daily_requests.*=0` 在任何真实工作前拒绝,
|
||||
出站为 0(真实 SDK 实测 C5 + tests/test_hard_gates_hel882.py)。
|
||||
2. 每次 search 恰好 1 条嵌入记账;并发预占不越 cap(C4/C6)。
|
||||
3. 对话同一轮绝不双发(chat_lock + 轮次幂等重放);预算到顶 0 次 provider
|
||||
调用、如实 chat.error(总管 api 复现已拦住,tests 复现)。
|
||||
4. 请求计数与 token 预占持久化,重启不归零(tests 双实例同库复现)。
|
||||
5. 语义作业:预算拒绝重排队不耗次数;真实错误 ≤3 次重试;租约回收与向量库
|
||||
级幂等保证不重发已入库行;stub→mem0 按后端区分覆盖,真实完成批不重发。
|
||||
6. SDK 隐藏重试已禁用(max_retries=0),被应答的失败照实入账;只有可证明
|
||||
未连接的预占才释放(总管 sdk 复现已拦住,tests 复现)。
|
||||
7. 主对话 token/请求与语义层独立闸,均发送前预占(含 Mem0 内部 LLM 并入
|
||||
`semantic` 类别 + 日 token 池)。
|
||||
@@ -1,6 +1,6 @@
|
||||
# CyberGril 需求入口
|
||||
|
||||
当前完整基准:**v1.11**。批准需求继承办法的主卡评论:`01a1635b-b47c-79ed-ac66-9408c7905af9`。
|
||||
当前完整基准:**v1.12**(HEL-899 起 v1.12;本行此前长期写 v1.11,属入口勘误,基准与变更记录本身自 v1.12 起即为准确,未回退)。批准需求继承办法的主卡评论:`01a1635b-b47c-79ed-ac66-9408c7905af9`。
|
||||
|
||||
所有新任务、续办、设计、施工、审核先读完整当前需求,再读本次相关来源。只有白栖知明确修改的要求才可变更,阶段范围不能覆盖产品要求。
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"schema_version": 1,
|
||||
"version": "1.11",
|
||||
"version": "1.12",
|
||||
"approval_comment_id": "01a1734c-1159-7a44-a81f-3105f1b8d98d",
|
||||
"owner_id": "e5c6c938-db48-4ff9-954f-4fb8b063a132",
|
||||
"scope": "完整要求;v1.11在v1.10的59项上新增成熟方案优先复用执行约束,原产品与验收边界保留;不代表已选定底座、授权迁移或功能通过。",
|
||||
@@ -118,10 +118,11 @@
|
||||
"category": "产品",
|
||||
"topic": "连续语音与文字",
|
||||
"conclusion": "用户主动开启语音后自然连续交谈,支持开口打断她;结束语音后停止收音,同时保留文字聊天。",
|
||||
"boundary": "响应速度、回声消除和打断效果需用现有语音服务实测,未承诺固定毫秒数。",
|
||||
"boundary": "响应速度、回声消除和打断效果需用现有语音服务实测,未承诺固定毫秒数。音色入口以可自定义音色为准:在网页上传或录制参考音频→试听→应用到同一位她的后续通话,直接复用已装TTS的零样本克隆;不以仅选预设音色替代,先前参考包试听方案不采用。本轮通话测试授权总管自定音色、最长2小时/3次通话;自定义音色交付不等于用户已验收音色,也不改变换声音只换发声、不重建伴侣、不改出生底色/名字/关系/聊天与记忆的边界。",
|
||||
"source_comment_ids": [
|
||||
"01a15750-2cf9-7f23-9269-0f150d2c5e61",
|
||||
"01a15750-e061-733b-9d80-38459d306b97"
|
||||
"01a15750-e061-733b-9d80-38459d306b97",
|
||||
"01a17de1-2892-78be-a422-eb6a11ffebfd"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
@@ -108,6 +108,16 @@
|
||||
"GOV-006"
|
||||
],
|
||||
"impact": "原59项保持;不预设保留自研底座,也不指定任何最终开源项目;未授权产品迁移、依赖安装、现网部署或改变资料/隐私边界。"
|
||||
},
|
||||
{
|
||||
"version": "1.12",
|
||||
"approval_comment_id": "01a17de1-2892-78be-a422-eb6a11ffebfd",
|
||||
"approved_by": "e5c6c938-db48-4ff9-954f-4fb8b063a132",
|
||||
"summary": "CG-010音色边界更新:以可自定义音色为准(网页上传/录制参考音频→试听→应用),直接复用已装TTS零样本克隆;不以仅选预设替代,参考包试听方案不采用;本轮通话测试授权总管自定音色、最长2小时/3次通话。",
|
||||
"affected_ids": [
|
||||
"CG-010"
|
||||
],
|
||||
"impact": "只改音色入口与测试授权;换声音只换发声、不重建伴侣、不改底色/名字/关系/聊天/记忆的既有边界不变;交付与阶段通过不等于用户已验收音色;不新增付费服务、不改变部署与资料边界。"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -39,3 +39,13 @@ v1.7:把原始31项、已确认视觉和后续用户裁定整理到同一入
|
||||
> 记住我的原则,能借鉴成熟方案的就直接借鉴,从零创造的难度太大需要的是一个专业的团队,不适用于我这个不专业的人加上没有决策性的AI的组合;另外我之前让你看的我跟另外智能体的交流内容希望你提取值得借鉴的地方
|
||||
|
||||
旧记录未明确规定通用内核必须优先复用成熟实现;现新增GOV-006,减少从零研发和长期自行维护,不因沉没工作量而默认保留自研内核。原59项不删减。交流材料提炼为候选机制,具体技术栈、底座、情绪映射及迁移范围未获批;不将本次文档记录当功能通过或现网施工授权。
|
||||
|
||||
## v1.12:音色入口定为可自定义音色
|
||||
|
||||
来源评论:`01a17de1-2892-78be-a422-eb6a11ffebfd`(2026-10-27 15:01:10 UTC,回应总管阻塞通报 `01a17d45-f14e-7b62-9850-646e040c7318`)。白栖知原话:
|
||||
|
||||
> .12已恢复,另外以上一条让我解压附件包试听,我不明白是什么意思,是让我听预设音色吗?如果是我觉得你的设计不够合理,我想要的是可以自定义音色,我的.12上安装的TTS是支持自定义音色的。至于最长2小时,3次通话的测试,我同意,音色你自己决定就行
|
||||
|
||||
旧边界(CG-010/D1 路线):音色按"先在现有中文女声里挑、都不满意再做零样本克隆"的条件路线推进,本轮以参考包编号试听为交付形式。新要求:**音色入口以可自定义音色为准**——在网页上传或录制参考音频→试听→应用到同一位她的后续通话,直接复用已装TTS的零样本克隆;不以仅选预设音色替代,参考包试听方案不采用。另明确:本轮通话测试授权总管自定音色、最长2小时/3次通话(操作授权,记 HEL-879 测试执行,不进需求边界)。
|
||||
|
||||
影响范围:仅 CG-010 音色入口与测试授权;换声音只换发声、不重建伴侣、不改出生底色/名字/关系/聊天/记忆的既有边界不变;CG-010 其余条文与原59项不动。工程交付或测试通过不等于用户已验收音色,也不得把"用户已授权自定义音色"改写成"用户已选定某支音色"。原话记录见 `sources/comment-evidence-custom-voice-20261027.json`(施工员2号按平台原话逐字核对录入)。
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"baseline_version": "1.11",
|
||||
"baseline_version": "1.12",
|
||||
"items": [
|
||||
{
|
||||
"requirement_id": "CG-001",
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
# CyberGril 完整当前需求 · v1.11
|
||||
# CyberGril 完整当前需求 · v1.12
|
||||
|
||||
完整要求;版本1.10在v1.9(交流静图认可)之上,把白栖知已体验的对坐动态小样 v2 整体效果(演示层面)记入 VIS-011 与 CG-004 边界;不证明其余页面、真实功能或完整产品已验收。
|
||||
|
||||
v1.11新增GOV-006成熟方案优先复用;原59项与v1.10阶段验收边界保持。
|
||||
|
||||
v1.12按白栖知2026-10-27原话(`01a17de1-2892-78be-a422-eb6a11ffebfd`)把CG-010音色边界更新为可自定义音色:网页上传/录制参考音频→试听→应用到同一位她的后续通话,直接复用已装TTS零样本克隆,不以仅选预设替代;先前参考包试听方案不采用。本轮通话测试授权总管自定音色、最长2小时/3次通话。该项交付不等于用户已验收音色。
|
||||
|
||||
## 阅读与效力
|
||||
|
||||
用户明确的新决定覆盖旧决定并记录来源;完整当前记录优先于任务摘录、技术方案和旧仓库 SPEC。无明确用户裁定的冲突先查来源,不擅自取舍。
|
||||
@@ -84,9 +86,9 @@ v1.11新增GOV-006成熟方案优先复用;原59项与v1.10阶段验收边界
|
||||
|
||||
用户主动开启语音后自然连续交谈,支持开口打断她;结束语音后停止收音,同时保留文字聊天。
|
||||
|
||||
边界:响应速度、回声消除和打断效果需用现有语音服务实测,未承诺固定毫秒数。
|
||||
边界:响应速度、回声消除和打断效果需用现有语音服务实测,未承诺固定毫秒数。音色入口以可自定义音色为准:在网页上传或录制参考音频→试听→应用到同一位她的后续通话,直接复用已装TTS的零样本克隆;不以仅选预设音色替代,先前参考包试听方案不采用。本轮通话测试授权总管自定音色、最长2小时/3次通话;自定义音色交付不等于用户已验收音色,也不改变换声音只换发声、不重建伴侣、不改出生底色/名字/关系/聊天与记忆的边界。
|
||||
|
||||
来源评论:`01a15750-2cf9-7f23-9269-0f150d2c5e61`、`01a15750-e061-733b-9d80-38459d306b97`。
|
||||
来源评论:`01a15750-2cf9-7f23-9269-0f150d2c5e61`、`01a15750-e061-733b-9d80-38459d306b97`、`01a17de1-2892-78be-a422-eb6a11ffebfd`。
|
||||
|
||||
## CG-011 · 主动联系范围
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"baseline_version": "1.11",
|
||||
"read_commit": "31970c4dd3851aae67a922b03264743d504b8e97",
|
||||
"task": "HEL-874 返工:补齐原话回读与真实记忆库接线——原话有界回读进入真实 provider 输入、实际固定 Mem0 SDK 合同核验并修复接线缺陷、预算闸可核验(嵌入预占制+内部 LLM 独立闸)、有确定上限的真实整体检查执行表、8360 隔离发布包、补记 2026-10-26 用户原话来源;不做部署、不合并、不启动用户真实循环、零真实调用",
|
||||
"requirement_ids": [
|
||||
"CG-006",
|
||||
"CG-008",
|
||||
"CG-011",
|
||||
"CG-012",
|
||||
"CG-013",
|
||||
"CG-014",
|
||||
"CG-015",
|
||||
"CG-016",
|
||||
"CG-021",
|
||||
"AM-001",
|
||||
"AM-002",
|
||||
"AM-003",
|
||||
"UX-004",
|
||||
"UX-006",
|
||||
"GOV-001",
|
||||
"GOV-002",
|
||||
"GOV-003",
|
||||
"GOV-005",
|
||||
"GOV-006",
|
||||
"DEL-001"
|
||||
],
|
||||
"deliverable": "在统一候选母线 hel-870-assembly(基线 31970c4 保留作前后对照)上完成四类修正,全部零真实模型/零嵌入/零出站(127.0.0.1 确定性假网关与本地模型缓存除外):1) 原话有界回读——memory/semantic.py chain_resolve 现返回锚定行的原话文本与时间戳,context() 把来源原话(每行≤200字窗口+可见截断标记)、角色、时间随命中注入模型上下文,摘要仅作一行指针,预算仍为 min(600,budget);memory/episodic.py context() 由『gist 优先截120字』改为原话优先(≤240字窗口)+角色+M月D日 HH:MM,gist 不再充当回读载荷;tests/test_readback_hel874.py 三例全部捕获真实发给 provider 的 messages(经 TestClient 全链):已退出近20轮窗口的旧轮细节(工牌编号A8823,gist 中不存在)原话进入模型输入且带角色与时间、语义链命中同样回读原话、未分享伴侣行原话在 FTS/语义两通道与任何锚点中都不出现(AM-001)。2) 实际固定 SDK 合同核验并修复——tools/verify_mem0_real_hel874.py 在 mem0ai 2.2.1(2c81af3,tarball SHA256 9dcef930 复核)固定安装上实跑:before(31970c4) 构造即死(同路径第二个 QdrantClient 被固定 SDK 拒绝,RuntimeError 已留证)、search 无 user_id 过滤被 2.2.1 直接 ValueError、limit 形参被静默忽略(正确为 top_k)、search 外层+包装双记账、内部提取 LLM 不过任何闸、并发 check-then-debit 可越 cap;after 全部修复(单client=SDK 自带 vector_store.client、add(user_id=)+search(filters,top_k)、包装为唯一记账点、LlmLedgerGuard 独立 llm_ops 表 cap 默认0、EmbedLedgerGuard 改预占-落账-释放事务制含过期预占清理)并 12/12 检查通过(C1构造/C2锚点与作用域与实测开销 1 LLM+2-3嵌入/C3默认提取输入集=旧记忆与滚动history均来自此前过门批次/C3b未分享canary零出站/C4过滤与单记账/C5双cap=0时出站LLM为0/C6并发不越cap/C7关闭恢复),证据 docs/rework/hel874/{real-sdk-before.json,real-sdk-after.json,README.md}。3) 预算闸可核验——临时隔离账实测(权威三账零写入);tests/test_mem0_backend.py 以镜像真实 2.2.1 表面的假SDK 9 例覆盖:双cap=0在任何真实工作前拒绝且 LLM 零调用、失败释放预占不记账、8路并发不越cap、llm_ops 计数、e2e 原话入块。4) 八字敏感度映射如实定案——mood_runtime 的阶梯 1.25/0.8(HEL-870 自造常数)改回原仓库奠基提交 1012d8b 既有连续规则 1.35-0.70*strength(bazi.sensitivity_from_strength 唯一处),并明确标注为工程启发式、非用户批准的命理科学事实;外部智能体材料中的固定公式未被采用(discussion-takeaways-20261025 不直接照搬清单)。另交 docs/budget-plan-hel874.md(A/B/C 三部分有确定上限执行表+代码级硬闸事实+授权来源,原20-30次/100-200条仅为估算的声明)、deploy/hel874-release.md + deploy/cybergril-hel874-8360.service.example(全新空数据目录、systemd、健康能力矩阵、停用与保留数据回退,未执行)、docs/requirements/sources/comment-evidence-full-experience-20261026.json(白栖知 2026-10-26 两条原话,01a17806 与 01a1780e『完整项目体验然后慢慢迭代』,作者/时间/父评论已核,manifest 只增新条目)、runbook §4/§6/§8 与 config/semantic.example.yaml 更新(llm_cap/user_scope/实测事实)。",
|
||||
"acceptance": [
|
||||
"原话回读进真实 provider 输入:tests/test_readback_hel874.py 3 例——旧轮细节原话(gist 无编号)+角色+时间出现在捕获的模型输入、语义链命中回读锚定行原话、未分享伴侣行原话与锚点双通道零泄漏(tests/test_readback_hel874.py)",
|
||||
"实际固定 SDK 合同:verify_mem0_real_hel874.py before(31970c4) 构造失败留证、after 12/12 通过(构造/锚点/作用域/提取输入集/canary/过滤/单记账/并发/双cap=0零出站LLM/关闭恢复),证据 docs/rework/hel874/",
|
||||
"预算闸:假SDK 9 例——embed/llm cap=0 在任何真实工作前拒绝(LLM 服务器零请求)、失败释放预占零记账、并发不越 cap、llm_ops 独立计数;权威三账与冻结余额零写入(tests/test_mem0_backend.py)",
|
||||
"八字敏感度:sensitivity_from_strength=1.35-0.70*strength 为原仓库既有程序规则(1012d8b),mood_runtime 回归该规则并如实标注工程启发式;外部智能体公式未采用(src/cybergril/core/bazi.py、mood_runtime.py 注释)",
|
||||
"执行表与发布包:docs/budget-plan-hel874.md 三部分有确定上限+授权来源;deploy/hel874-release.md+systemd example 全新空目录/健康矩阵/回退,未部署未合并未交体验地址",
|
||||
"用户原话来源:sources/comment-evidence-full-experience-20261026.json 只增两条原话及来源校验,manifest 增一条,baseline/current/coverage/changes 零改动(GOV-002 不擅改完整要求)",
|
||||
"工程检查:python 3.11 venv 全套 256 项测试通过、ruff 0 错、web typecheck+vitest+build 通过;双目标需求结构检查 4/4 通过(含本 handoff)"
|
||||
],
|
||||
"deferred": [
|
||||
"统一候选独立复审与发布:由总管对最终 head 独立复审(本卡作者不自行宣布通过);通过并按 A/B 预算批准后由发布卡执行 deploy/hel874-release.md(8360 隔离实例),本卡未部署未合并 PR#11 未交体验地址",
|
||||
"真实语义激活(CYBERGRIL_SEMANTIC=mem0):待 B 部分预算批准(embed_cap/llm_cap>0)后执行;固定 venv 并入产品进程的方案由发布卡决定",
|
||||
"真实整体检查 A/B/C 三部分执行:待总管核定并向白栖知申请授权(docs/budget-plan-hel874.md);本卡零真实调用",
|
||||
"R5 语音/R6 天气、素材、备份/R7 视觉观察承接不变(runbook §7);视觉仍交原作者;HEL-835 未解闸、39/60 与 498/500 冻结不动",
|
||||
"原话回读的用户体验效果(回读量是否恰当、是否影响语气)属体验验收,待统一体验地址交付后由白栖知判断"
|
||||
],
|
||||
"requirement_changes": [],
|
||||
"verification": [
|
||||
"分支 hel-870-assembly 追加提交(最终 head 见交付评论),PR#11 更新未合并未强推;视觉总监分支未覆盖",
|
||||
"python 3.11.16 venv + requirements.lock 离线安装:256 项测试全过(新增 test_readback_hel874.py 3 例、test_mem0_backend.py 重写为真实 2.2.1 表面镜像 9 例);ruff 0 错;web typecheck/vitest/build 通过",
|
||||
"真实固定 SDK 验证:hel857-venv(3.10.12+mem0ai 2.2.1+已有 fastembed 缓存只读)实跑 before/after 双证据 JSON;零真实出站(LLM=127.0.0.1 假网关)、零权威账写入",
|
||||
"python3 scripts/check_requirements.py --base-ref origin/main [--handoff docs/requirements/handoff-HEL-874.json] 与 --base-ref origin/agent/agent/de8874a3803b [--handoff …] 四项通过"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"baseline_version": "1.11",
|
||||
"read_commit": "31970c4dd3851aae67a922b03264743d504b8e97",
|
||||
"task": "HEL-876:核清 .12 已有语音底座真实状态并把 R5 语音接入工程材料备齐;同步只读核对 R6 接缝;零真实模型/嵌入/合成/识别请求,不改现网",
|
||||
"requirement_ids": [
|
||||
"CG-006",
|
||||
"CG-009",
|
||||
"CG-010",
|
||||
"CG-018",
|
||||
"CG-019",
|
||||
"CG-020",
|
||||
"CG-021",
|
||||
"CG-022",
|
||||
"CG-023",
|
||||
"CG-028",
|
||||
"CG-029",
|
||||
"CG-030",
|
||||
"CG-031",
|
||||
"AM-001",
|
||||
"GOV-001",
|
||||
"GOV-002",
|
||||
"GOV-003",
|
||||
"GOV-004",
|
||||
"GOV-005",
|
||||
"GOV-006",
|
||||
"DEL-001"
|
||||
],
|
||||
"deliverable": "docs/voice-r5-readiness-HEL876.md(带时间戳的 .12 只读核查:7880/10095/8090 存活证据、8081=voice worker 的身份修正、9880 TTS 于 2026-10-24 22:17 优雅停机未运行、8010 MuseTalk 单元已不存在、8188 ComfyUI 占 26.6GB 显存致空闲仅 3.9GB<所需 5.6GB、音色表 11 支与当前 rain、两个 venv 版本、.11 网关与 open-meteo 探活;R5 worker 复用 app.py:488 同一 chat 链的接缝与协议;R6 城市天气/素材/备份四处接缝定位;三栏结论与零成本工程清单)+ scripts/verify_hel876_voice_seam.py 离线零模型协议检查(六项全过:epoch 同步、完整轮含 receipt、replay 零重复调用、received 确认、barge-in 新轮取消旧行=cancelled、409 重同步)。src/ 与 web/ 零改动,无新产品 PR。",
|
||||
"acceptance": [
|
||||
"端口/进程/健康证据全部为本轮 2026-10-26 13:22-13:38 UTC 实测,未照抄 8090/8081 旧解释:8081 实为 livekit-agents worker(pid 451883),MuseTalk 8010 单元已不存在,TTS 9880 停机(tts.log 优雅停机于 10-24 22:17)",
|
||||
"凭据与 token 未读取未输出;.env 仅列白名单字段名;证书/防火墙/系统环境未改;未启停任何服务;未访问 4080;零真实 LLM 对话/嵌入/合成/识别请求",
|
||||
"语音 worker 复用同一条业务链的结论落到文件/行为级:chat 链六项协议性质(epoch/串行/取消/replay/receipt/断开清理)以 fake provider 离线证明,全部通过;明确该证明不等于端到端真实通话通过",
|
||||
"R5 材料备齐:目录/端口/worker 方案、复用依赖与版本、启动顺序与 TTS 重启命令、音色候选清单(无用户决定则不替定,D1 附试听/克隆真实入口及 TTS 停机期间不可试听的如实说明)、D3 麦克风用户动作、GPU 时段协调项",
|
||||
"R6 只读核对只定位不实现:城市(ManagePanel.tsx:182 占位、后端无代码)、天气(无代码、open-meteo 出网已证)、素材 manifest(仅演示态 :178/:183、后端无代码)、备份边界(companion.db+vec_public+mem0_public_history.db+嵌入账本,复制单 .db 不算完整;Persona.fingerprint 可作同一位她校验)",
|
||||
"三栏结论如实:已证实/未验证/确实缺资源(GPU 3.9GB<5.6GB 为唯一硬缺口);零成本工程清单六项;文档独立分支提交、候选 PR 不合并"
|
||||
],
|
||||
"deferred": [
|
||||
"R5 真实验收:连续 3 轮、开口打断 ~1s 停声、结束即停麦、无残音、移动端麦克风——TTS 恢复并接好 worker 后在 R5 施工卡执行",
|
||||
"TTS 重启:需 GPU 空闲≥6GB(ComfyUI 释放协调),由总管与白栖知安排时段,本卡未执行任何启停",
|
||||
"D1 音色最终决定与 D3 用户设备信任操作:交总管集中沟通;D2 天气源采纳、D4 视觉观察仍按原依赖待用户决策",
|
||||
"R6 城市/天气/素材/备份的实现(本卡仅定位接缝):建议总管按 §7 零成本清单连续派工",
|
||||
"统一候选独立审核部署(8360)与语音产品代码增量(/api/voice/session、HTTPS 口、前端语音按钮):后续卡"
|
||||
],
|
||||
"requirement_changes": [],
|
||||
"verification": [
|
||||
"SSH 只读核查 2026-10-26 13:22-13:38 UTC(ss/ps/systemctl/docker/nvidia-smi/curl/日志尾部/源码阅读),未做任何写操作",
|
||||
"scripts/verify_hel876_voice_seam.py 于 3.11 venv(uv 离线缓存安装,零下载)+ requirements.lock 全过六项;ruff 0 错",
|
||||
"check_requirements.py 双目标(origin/main 与 origin/hel-870-assembly)含本 handoff 退出码 0",
|
||||
"未验证并如实声明:本轮端到端语音可用性(TTS 停机)、真机移动端麦克风、TTS 恢复后延迟"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"baseline_version": "1.11",
|
||||
"read_commit": "31970c4dd3851aae67a922b03264743d504b8e97",
|
||||
"task": "HEL-877:把已核清的语音底座接到统一 CyberGril 业务链(获批 R5 后台施工);新增专属 livekit worker(agent_name=cybergril-voice-agent,复用 .12 FunASR/CosyVoice/silero VAD,不 fork 不另搭平台)+ 统一实例 POST /api/voice/session 最小协议(建房/专属派发/短时限 token 服务端处理,密钥不进浏览器)+ 与文字前端同协议的 livekit LLM 适配器(POST /api/chat,SSE/epoch 409 有界重同步/turn_id 幂等/打断即断流)+ SDK 真实播放完成才确认的分享回执;零真实请求自测交可审核代码",
|
||||
"requirement_ids": [
|
||||
"CG-006",
|
||||
"CG-010",
|
||||
"CG-011",
|
||||
"CG-013",
|
||||
"CG-014",
|
||||
"CG-015",
|
||||
"CG-016",
|
||||
"CG-018",
|
||||
"CG-019",
|
||||
"CG-020",
|
||||
"CG-021",
|
||||
"AM-001",
|
||||
"GOV-001",
|
||||
"GOV-002",
|
||||
"GOV-003",
|
||||
"GOV-004",
|
||||
"GOV-005",
|
||||
"GOV-006",
|
||||
"DEL-001"
|
||||
],
|
||||
"deliverable": "src/cybergril/voice/ 独立模块:session.py+router.py(POST /api/voice/session、DELETE 结束删房释放麦克风/job、GET /api/voice/status 诚实开关;缺配置/无档案/TTS 不可用如实拒绝;app.py 仅最小注册且 capabilities.voice 不伪造)、livekit_wire.py(零新依赖 HS256 token+Twirp 派发/删房,与已装 SDK 同线上格式)、chat_api_client.py(与 real.ts 同协议:health epoch、SSE 分片鲁棒解析、409 一次重试、固定 turn_id、打断 finally 即断流)、llm_chat_api.py(livekit llm.LLM 适配器,只发当前用户话轮,服务端组装全部人格/记忆/关系;φ 原句经 ChatChunk 念出无回执)、receipt.py(should_ack 只有 played_to_end 且未打断未失败且带完整 receipt 且 epoch 一致才确认;TurnLedger 绑定 speech handle↔流;确认恰好一次)、stt_funasr.py/tts_cosyvoice.py(.12 已验证适配器原样复用带出处)、worker.py(agent_name=cybergril-voice-agent、独立 voice_state_cybergril.json 音色、无第二人格、cg.subtitle 字幕数据通道、CG-011 主动开口空操作接缝、专属健康端口 8082);config/voice.example.yaml 与 deploy/voice/{worker.env.example,restart_cybergril.sh.example,serve_dual_8360_8361.py} 部署草案(HTTP 8360+HTTPS 8361 同进程双入口共用同一状态/锁,runbook 含启动顺序/回滚/GPU 前置);docs/runbook-hel877-voice.md 契约+部署文档;tests/test_voice_session.py(9)+test_voice_chat_adapter.py(16)、scripts/verify_hel877_voice_chain.py、scripts/gen_hel877_sdk_check.py",
|
||||
"acceptance": [
|
||||
"语音轮次走统一链被证明:worker 适配器只调 POST /api/chat,文字/语音互相打断由服务端同一 chat_lock 轮次门处理(本地 socket 实测:语音打断文字轮旧行=cancelled 无幽灵行、打断取消即刻断 HTTP 流旧行 fail-closed、新轮干净)",
|
||||
"完成轮重放不新增模型调用;409 旧 epoch 一次有界重同步后成功;SSE 多字节/CRLF/多行 data 分片边界解析正确;turn_id 固定使 SDK 内部重试幂等",
|
||||
"分享 receipt 仅在 SDK 真实播放完成后确认:should_ack 对被打断/播放失败/未播完/φ 轮/残缺回执/旧 epoch 全负例拒绝(测试覆盖),确认恰好一次,服务端仍独立 fail-closed 校验",
|
||||
"POST /api/voice/session 服务端建房+专属派发(agent_name=cybergril-voice-agent,protobuf CreateDispatch 与已装 SDK 同格式)+短时限 token(TTL≤300s,与 livekit.api.AccessToken 声明集全等,.12 真 SDK 比对通过);房间隔离(两 session 不同房、token 各自房间);DELETE 删房结束;缺配置/无档案/TTS 停机诚实拒绝且 capabilities.voice 保持 false",
|
||||
"worker 不持有第二人格/记忆、不直连 LLM、不读通用助手 persona_state/voice_state(独立 voice_state_cybergril.json,D1 未拍板回落 default);CG-011 语音主动开口留明确空操作接缝并写清边界(仅已开启会话、同业务链、可打断、不新回执通道)",
|
||||
"真 SDK 兼容在 .12 agent venv(livekit-agents 1.8.8)stdin-only 零写入零网络验证 8 项全过(真 LLM/LLMStream 子类、真 ChatContext、真流机制 ChatChunk+final+receipt、φ ChatChunk、token 声明集与 SDK AccessToken 全等、server token 同形、SpeechHandle/事件 API 存在、打断取消立即关流)",
|
||||
"双入口同进程:本地 18360/18361 冒烟单 pid 双端口同 epoch 两端诚实拒答;HTTP 与 HTTPS 共用同一 app 对象/状态/锁,无第二实例写同一 DB",
|
||||
"部署草案齐全(/opt/voice-agent-cybergril、健康端口 8082、启动顺序含 TTS GPU≥6GB 前置、回滚、禁抄历史 fuser 命令的明确警告);本卡未执行任何部署/启停/下载安装,未动 web/、三账、档案、4080、现网服务"
|
||||
],
|
||||
"deferred": [
|
||||
"R5 真机验收:连续 3 轮、开口打断 ~1s 停声、结束停麦无残音、移动端 Safari/Chrome 麦克风——TTS 恢复(GPU 需 ≥5.6GB,现 3.9GB,ComfyUI 不停)并接线后在后续卡执行;未经真实验收不得称 R5 完成",
|
||||
"视觉总监接线:语音按钮/字幕(cg.subtitle)/失败/打断/挂断按 runbook §3 契约;本卡未改 web/",
|
||||
"总工独立审核与部署(runbook §4):.12 上对真 LiveKit server 的 dispatch/delete、HTTPS 证书签发与实机信任(每台手机高级→继续)待实测,不承诺每台手机点继续必然可用",
|
||||
"语音内主动开口(CG-011 接缝)与 D1 音色最终决定、D3 用户设备动作、GPU 时段:总管集中与白栖知沟通",
|
||||
"R6 天气/素材/完整备份承接不变;视觉观察默认关闭不变"
|
||||
],
|
||||
"requirement_changes": [],
|
||||
"verification": [
|
||||
"PYTHONPATH=src .venv311/bin/python -m pytest tests -q:281 passed(总工 HEL-874 返工后全量 256 + 本卡 25,含语音会话 9 与适配器/回执 16,全 fake HTTP/SSE/本地 127.0.0.1 socket,零真实模型/嵌入/合成/识别)",
|
||||
"scripts/verify_hel877_voice_chain.py 一键全链 8 项全过(真实 app + fake LiveKit/TTS + 本地 socket:拒答序/专属派发/短时限 token/房间隔离/删房结束/多轮回执/重放零调用/409 重同步/打断 fail-closed/播放完成回执一次/capabilities.voice=false)",
|
||||
"scripts/gen_hel877_sdk_check.py 生成脚本经 SSH stdin 在 .12 /opt/voice-agent/agent/venv/bin/python(livekit-agents 1.8.8、livekit 1.1.20)执行:8 项 ALL PASS(零写入、零网络、未触任何服务)",
|
||||
"双入口本地冒烟:一次性自签证书(本机 openssl 生成)+ deploy/voice/serve_dual_8360_8361.py 于 18360/18361,单 pid、同 epoch、/api/voice/status 诚实、未配置 POST 503;测后进程与端口已释放",
|
||||
"ruff check src tests scripts deploy:本卡代码 0 错(唯一遗留 SIM115 属既有 deploy/hel835_guard.py,非本卡);check_requirements.py 双目标(origin/hel-870-assembly 现tip e978e87 与 origin/main)含本 handoff 通过",
|
||||
"读取位置记录:开工时 origin/hel-870-assembly=31970c4 与卡文一致;施工中总工推入 HEL-874(e978e87),本卡已完整 merge 保其成果不覆盖;origin/hel-876-voice-readiness=23415fb(总管读取点)已并入",
|
||||
"未验证如实声明:端到端语音(TTS 停机未连麦)、真 LiveKit server 的 dispatch/delete 实测、worker 运行时行为(字幕/VAD/回声抑制仅源码级对齐 .12 已验证实现与 SDK 静态契约)、移动端实机"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
{
|
||||
"baseline_version": "1.11",
|
||||
"read_commit": "bf234570c0b6595a72f8dbc79e42c63685e08e01",
|
||||
"task": "HEL-878(R5 前端接线,视觉总监本人设计并编码):在已认可的交谈界面上由用户主动开启/结束连续语音;按 HEL-877 后台契约(aba2aeb docs/runbook-hel877-voice.md §3)接 GET /api/voice/status、POST/DELETE /api/voice/session 与 cg.subtitle 字幕,复用 .12 :8090 既有 livekit-client 2.22.4 浏览器客户端;文字与语音同一位她、同一聊天记录,轮次从 /api/messages 回读不串台;所有退出路径立即停麦并清理;零真实模型/嵌入/合成/识别/采集/部署",
|
||||
"requirement_ids": [
|
||||
"CG-006", "CG-010", "CG-011", "CG-018", "CG-020",
|
||||
"VIS-001", "VIS-002", "VIS-003", "VIS-004", "VIS-005", "VIS-006", "VIS-007", "VIS-008", "VIS-009", "VIS-010", "VIS-011", "VIS-012", "VIS-013",
|
||||
"UX-001", "UX-002", "UX-005", "UX-006",
|
||||
"AM-001",
|
||||
"GOV-001", "GOV-002", "GOV-003", "GOV-004", "GOV-005", "GOV-006",
|
||||
"DEL-001"
|
||||
],
|
||||
"deliverable": "自前端原稿 hel-875-proactive-wiring @ bf23457 起的补丁(仅 web/ 与本交接):1) web/src/voice/session.ts——VoiceController 生命周期(代次计数:任何迟到的 token/房间/麦克风/房间事件只清理不显示);顺序为诚实状态(只 GET status,不建房不采麦)→ 加载客户端 → 采麦(拒绝则服务端什么都不开)→ POST session(结束时已在途的请求等其返回并 DELETE,不留孤儿房)→ 加入并发布麦克风 → 等 worker 加入(20 s 未加入如实失败);状态取 worker 的 lk.agent.state,缺属性时按字幕保守推断;interim 为草稿、user_final 取消在途文字回复并触发回读、assistant_final 触发回读、error(φ) 只显示「未记入聊天」不入记录;文字盖过她的语音时静音残余音频直到她回到聆听;结束顺序为停麦→关房间与音频→DELETE;断网时本地立即停采,远端 DELETE 记入本浏览器 cg.voice.owed,恢复网络/再次进入/再次开启时补发(404 视为已清);页面卸载用 keepalive DELETE;mergeTurns/recentRows 只合并非主动留言的服务器行(主动留言仍走原 inbox 轮询),按 turn_id 与已有文字轮去重,pending 行回读至落定。2) web/src/voice/livekit.ts——同源懒加载 /vendor/livekit-client-2.22.4.umd.min.js(来源 .12:8090/static,SHA-256 见 web/VENDOR.md,未改 package.json/锁文件),回声消除采集、她的音频集中在隐藏容器(结束即暂停/清空/移除)、自动播放受阻时提供「点一下听她的声音」、加入可被结束即时中止。3) ChatPanel.tsx——真实模式麦克风按钮按状态诚实标注(不可用时淡化并说明原因),确认框说明麦克风、去向、同一份记忆、如何打断与停止、未经真机验收;沿用原演示 voice-row 位置与视觉语言做成玻璃单行(连接/等待为呼吸、聆听用你的颜色、她说话用她的光色,文字始终写明状态);文字流在无 final 时先查服务器行:被新轮取消即按已取消处理,不报连接中断、不回填草稿;离开交谈/Esc/结束交谈/导航卸载面板即结束语音;在途语音轮期间她的主动留言照原规则排队。4) RealApp.tsx——语音进行中顶栏写「语音(未经真机验收)」。5) components.css 新增 .voice-row.real 等样式(含手机)。6) 测试:web/tests/voice.test.ts 26 项;web/tests/hel878_mock.mjs(HEL-877 路由契约 mock)+ fake-livekit.js(脚本化替身,浏览器假音频设备)+ hel878_shots.mjs 浏览器检查 45 项与截图;web/VENDOR.md、README 语音段落。",
|
||||
"acceptance": [
|
||||
"到达交谈页只发一次 GET /api/voice/status:不建房、不申请麦克风、不加载 LiveKit 客户端;configured=false / tts_ok=false / 无路由各有诚实说明,按钮淡化且不弹确认;voice=false 不被当作已接通(浏览器 1–2、单测 honest switch)",
|
||||
"用户确认后:一个会话、一个麦克风、发布到该房间;等待 worker 时显示等待而非已接通;聆听/思考/说话随 lk.agent.state 切换;字幕草稿、φ 原句(标未记入聊天且不入记录)均按契约(浏览器 4–6)",
|
||||
"语音轮只从 /api/messages 进入舞台与完整记录,各一次,与文字同一段记录(浏览器 5);前端从不 POST /api/chat 或 /api/chat/received(单测)",
|
||||
"双通道:文字盖过她说话时残余音频静音、回到聆听再恢复;语音打断在途文字回复时该轮按已取消处理,无“连接中断/重试”、不回填草稿,记录显示已取消(浏览器 7–8)",
|
||||
"结束语音/导航离开/Esc/结束交谈/房间掉线/麦克风被撤销/服务端拒绝/重复开关后:本地麦克风 track 全部 ended、她的音频与容器移除、服务端房间删除;迟到事件不复活旧会话(浏览器 10–14,单测 lifecycle 15 项)",
|
||||
"断网:本地立即停麦停音频,远端房间如实记为欠删(不冒充已删);恢复网络后补发 DELETE 并清除记录;页面卸载 keepalive DELETE 到达(浏览器 14);欠删跨页面保留、404 视为已清(单测)",
|
||||
"电脑 1440×900 与手机 390×844(2x)、月光/雾光两主题截图;手机语音行不出屏(浏览器 15)",
|
||||
"真实 livekit-client 2.22.4 构建中,适配器用到的全部名称存在(RoomEvent 七项、Track.Source.Microphone、ParticipantKind.AGENT、createLocalAudioTrack、Room 方法/属性);仅 API 面核对,未连接",
|
||||
"演示入口零语音请求;工程:tsc 0 错,eslint 0 错(1 条既有警告),vitest 7 文件 81/81,vite build 通过"
|
||||
],
|
||||
"deferred": [
|
||||
"真实通话全部未测(R5 真机验收交 HEL-879 统一审核):连续 3 轮、开口打断约 1 s 停声、结束停麦无残音、回声、首包延迟、移动端 Safari/Chrome 麦克风与自动播放、自签 HTTPS 信任;浏览器检查用的是脚本化 LiveKit 替身与 Chromium 假音频设备,不是 WebRTC 通话",
|
||||
"lk.agent.state 属性名按 livekit-agents 1.x 惯例接入,并在缺失时用字幕推断;worker 实际是否发布该属性须真机确认",
|
||||
"断网时服务端房间的即时删除在物理上做不到:依赖 worker 在浏览器参与者离开后结束任务与会话登记过期(runbook §3.4/3.5,后台行为未在本卡实测),本页恢复网络或下次进入时补发 DELETE",
|
||||
"CG-011 语音内主动开口:worker._maybe_open_proactive 仍是空操作,前端未虚构;后台最小需求见 runbook §3.6(会话内取已落库 proactive 行 session.say 原文、可打断、无新回执通道),呈现节奏待总管/视觉总监另定;目前语音开启时她的主动留言仍以文字进入并在她思考/说话时排队",
|
||||
"她说话时没有逐字字幕(契约只在播放完成后发 assistant_final);舞台在落库后呈现全文。若要边说边显示需后台发增量字幕,属契约变更",
|
||||
"D1 音色、D3 设备信任、测试额度由总管与白栖知沟通;本卡未接触任何服务、凭据或部署",
|
||||
"原版 Python 需求检查未在本运行时执行(无 Python、无 git),须总管/总工对实际目标分支与 origin/main 含/不含本交接复跑;需与 HEL-882 最新母线同步后再审",
|
||||
"R6 天气/素材/备份、R7 视觉观察、CG-028/029 口型与真实视频仍由主卡 HEL-797 承接;整体沉浸体验由白栖知验收"
|
||||
],
|
||||
"requirement_changes": [],
|
||||
"verification": [
|
||||
"读取:前端 bf234570(总管输入包 frontend/,HEL-875/880 原作者原稿);后台契约 aba2aeb(输入包 voice-backend/:runbook-hel877-voice.md、voice/router.py、session.py、worker.py、handoff-HEL-877.json、requirements v1.11 含 comment-evidence-full-experience-20261026.json);已读 AGENTS.md、README/current(CG-006/010/011/018/020、UX-005/006、VIS-013)/coverage/changes、integration-plan-v1 R5 与 D1/D3、voice-r5-readiness-HEL876.md",
|
||||
"web:tsc --noEmit 0;eslint src 0 错;vitest run 7 文件 81/81(原 55 + 语音 26,含变异检查:去掉迟到授权回收或代次判定各使对应用例失败);vite build 通过(node_modules 沿用 HEL-875 同一锁文件离线树,无新增依赖、无下载)",
|
||||
"浏览器:node tests/hel878_mock.mjs 8878 + node tests/hel878_shots.mjs <msedge.exe> <out> 8878,45/45(无头 Edge,--use-fake-device-for-media-stream;脚本化 LiveKit 替身;本机回环);中断前一轮为 39/43,失败的 4 项(语音打断文字误报、断网远端清理、卸载检查受其连带)经本轮修复后通过",
|
||||
"唯一外部读取:一次只读 GET .12:8090 页面及其 /static/livekit-client.umd.min.js 以复用既有客户端;无模型、嵌入、合成、识别请求,无真实麦克风/摄像头,无部署或服务改动",
|
||||
"需求结构检查:本运行时无 Python/git,未执行原版脚本,不声称通过;仅用 HEL-875 留下的 Node 移植版辅助:以 bf23457 为基含本交接通过(60 项);以后台 aba2aeb 的需求文件为基失败「历史来源必须保留」,原因是该线已追加 comment-evidence-full-experience-20261026.json 而前端原稿尚未包含,与本补丁无关,合入母线前须先同步该需求目录"
|
||||
]
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"baseline_version": "1.11",
|
||||
"read_commit": "e978e878dfc34f38c781d48f87b93dc21bbf8a61",
|
||||
"task": "HEL-882 返工(总管对 HEL-874 e978e87 独立复审后的一次归拢修正):执行表上限落成真实硬闸(所有真实 provider 出口发送前持久预占请求次数与保守 token、按最紧约束拒绝、重启不归零,含 Mem0 内部提取 LLM 并入统一闸;拒绝新账本文件绕过冻结)、SDK 隐藏重试与中途失败/恢复修齐(max_retries=0 逐次受闸、被应答失败照实入账、吞错识别为预算拒绝并重排队续跑、向量库级幂等不重发不丢行、stub→mem0 按后端区分覆盖)、发布包修到离线可执行(空目录 checkout、PYTHONPATH 服务导入、服务账号/权限、mem0 同进程导入准确缺项与不下载路径、空账初始化、回环离线核验脚本)、HEL-874 嵌入证据口径勘正与验证工具边界改确定性替身;零真实调用、零真实嵌入、零非回环出站、不改视觉、不部署、不合并、不碰权威三账与冻结余额",
|
||||
"requirement_ids": [
|
||||
"CG-006",
|
||||
"CG-008",
|
||||
"CG-011",
|
||||
"CG-013",
|
||||
"CG-014",
|
||||
"CG-015",
|
||||
"CG-016",
|
||||
"CG-021",
|
||||
"AM-001",
|
||||
"AM-002",
|
||||
"AM-003",
|
||||
"UX-004",
|
||||
"UX-006",
|
||||
"GOV-001",
|
||||
"GOV-002",
|
||||
"GOV-003",
|
||||
"GOV-005",
|
||||
"GOV-006",
|
||||
"DEL-001"
|
||||
],
|
||||
"deliverable": "在统一候选母线 hel-870-assembly(基于 e978e878 追加,PR#11 只追加不强推)上完成四类修正:1) 硬闸——think/budget.py 增类别请求上限(dialogue/life/background/semantic,默认 0=拒绝)与一次性总量(A 部分)、BudgetStop、acquire/settle/release 预占制与保守 token 估算口径;life/model.py PersistentBudget 落库 request_usage/budget_total(r4.sql 新表,BEGIN IMMEDIATE 原子预占);api/app.py 主对话发送前 acquire、真实 usage 按实落账未知保守保留;structured() 全部后台出口同一闸;Mem0Backend 内部提取 LLM 接统一 request_guard(semantic 类别+日 token 池);EmbedLedgerGuard/LlmLedgerGuard 增日顶(embed_daily/llm_daily)与 verify_ledger_authority 冻结前缀校验(新空文件绕过 498/500 被拒);config/models.yaml 与 semantic.example.yaml 随包显式 0。2) SDK 边界与恢复——SDK client max_retries=0 禁隐藏重试;被网关应答过的失败照实入账、仅 httpx.ConnectError 级未发送释放;mem0 phase3/7 吞掉的嵌入预算拒绝经线程局地失败记录重抛,作业批遇预算拒绝回 queued 不耗 attempts,调 cap 后续跑;add_group 以向量库 src_group 锚做行级幂等(续传只发缺行、崩溃/重启/并发不重复发送);sem_covered 按后端区分(stub 批次不阻塞真实重建、mem0 完成批不重发),batch_key 含后端。3) 发布包——deploy/hel874-release.md 重写(空目录 git clone、cybergril 服务账号、PYTHONPATH 单元、models.yaml 硬闸默认 0 的设计行为说明);deploy/cybergril-hel874-8360.service.example 加 PYTHONPATH/Group;deploy/mem0-stack.lock 固定栈清单 + §4 准确缺项(hel857-venv 为 3.10、产品 3.11、缓存无 3.11 wheel,发布卡落 wheel 后同 venv 离线并入,本卡零下载)与不许 stub/FTS 冒充真实记忆体验;tools/check_release_offline_hel882.py 离线核验(R1 空目录 checkout/R2 服务 import+health/R3 未批上限 fail-closed/R4 批准后全链 echo 替身/R5 停止保留数据重开 epoch+1/R6 mem0 同进程导入现状)。4) 证据勘正——docs/rework/hel874/erratum-hel882.json 与 README 追加:e978e87 版验证读取缓存做过真实本地嵌入(可证下限 12 条、精确总数不可恢复)、提交信息与执行表『零真实嵌入』口径不成立、LLM=假网关/零下载/零出站口径仍成立;tools/verify_mem0_real_hel874.py 改为 TextEmbedding 构造前装确定性 512 维替身+socket 禁非回环(总管复现同口径),证据 JSON 落盘 final_embed_rows/final_llm_used 后再清临时目录;旧前后 JSON 与权威三账一律不改。验证:3.11.16 venv+requirements.lock 离线 272 项 pytest 全过(新增 tests/test_hard_gates_hel882.py 7 例:总管 api 复现拦住/类别日顶跨重启持久/后台类别闸/默认全拒绝/最紧约束与落账/持久计数器/一次性总量,tests/test_semantic_recovery_hel882.py 9 例:总管 sdk 复现拦住(1 次 HTTP、llm_ops=1)/未连接才释放/中途吞错重排队续跑/断点续传不重发/stub→mem0 重整与真实批不重发/嵌入日顶/内部 LLM 统一闸/authority 拒新文件/build_semantic fail-closed),ruff 0 错(src/tests/tools),web tsc+42 vitest+build 通过(npm ci --offline 零下载),固定 3.10 mem0 安装上确定性替身实跑 12/12(verify 工具)+总管两复现脚本复跑证据(见交付评论附件);零真实调用、零真实嵌入、零非回环出站,权威三账与冻结余额未写,未部署未合并未交体验地址,不改视觉。",
|
||||
"acceptance": [
|
||||
"总管 api 复现被拦住:日 token 已超限的轮次 0 次 provider 调用、如实 chat.error、计数不增(tests/test_hard_gates_hel882.py::test_daily_token_wall_refuses_before_any_provider_call)",
|
||||
"总管 sdk 复现一被拦住:llm_cap=1 面对本地 500 恰 1 次 HTTP、llm_ops 已用=1、第二次 add 发送前拒绝;SDK client max_retries=0(test_hidden_retries_disabled_and_wire_hits_counted)",
|
||||
"总管 sdk 复现二可恢复:embed 中途预算拒绝不再误写 done/[],批回 queued 不耗次数,调 cap 后同一批续跑 done 且 entry_ids 非空(test_mid_add_budget_swallow_requeues_then_resumes)",
|
||||
"总管 sdk 复现三修复:stub 完成批不再阻塞 mem0 重建(enqueue=1、检索命中),mem0 完成批不重发(test_stub_batches_never_block_real_rebuild_and_real_never_resends)",
|
||||
"断点续传:已入库行不重发、只补缺行;崩溃/重启后向量库级幂等(test_resume_never_loses_or_duplicates_rows)",
|
||||
"请求计数与 token 预占持久化跨重启;类别日顶/一次性总量/日 token 按最紧约束拒绝;未批类别默认 0 全拒绝(test_dialogue_request_cap_persists_across_restart 等)",
|
||||
"冻结防绕过:authority 前缀校验拒绝新空文件+cap>0 组合;build_semantic fail-closed(test_authority_block_refuses_a_fresh_file_bypassing_the_freeze)",
|
||||
"发布命令离线可用:check_release_offline_hel882.py 全过(R1–R6),mem0 同进程导入缺项如实记录且解决路径不下载",
|
||||
"证据勘正落地:erratum-hel882.json+README 追加,verify 工具确定性边界(零模型加载)实跑 12/12;旧前后 JSON 未改、权威三账未写",
|
||||
"工程检查:272 pytest、ruff 0(src/tests/tools)、web typecheck/42 vitest/build、双目标需求检查 4/4(含本 handoff)"
|
||||
],
|
||||
"deferred": [
|
||||
"发布与体验地址:由总管独立复审本 head 后交发布卡按 deploy/hel874-release.md 执行(8360 隔离实例);本卡未部署未合并 PR#11 未交体验地址",
|
||||
"真实语义激活(CYBERGRIL_SEMANTIC=mem0):需 B 部分预算批准 + 3.11 mem0 栈 wheel 落位(deploy/mem0-stack.lock,本卡零下载);未激活前 stub/FTS 不冒充真实记忆体验",
|
||||
"A/B/C 执行表数值仍为待批建议(docs/budget-plan-hel874.md):批准前所有 cap 保持 0=拒绝;新增预算由总管向白栖知一次性申请",
|
||||
"R5 语音/R6 天气、素材、备份/R7 有条件观察承接不变;视觉仍交原作者,本卡未改视觉",
|
||||
"真实体验效果(含硬闸拒绝时用户侧措辞是否需人设化)待体验地址交付后由白栖知判断"
|
||||
],
|
||||
"requirement_changes": [],
|
||||
"verification": [
|
||||
"分支 hel-870-assembly 追加提交(最终 head 见交付评论),PR#11 只追加未强推未合并;视觉总监分支未覆盖",
|
||||
"python 3.11.16 venv + requirements.lock 离线:272 项测试全过(新增 16 例硬闸/恢复测试);ruff 0 错(src/tests/tools);web typecheck/vitest 42/build 通过(npm ci --offline)",
|
||||
"固定 mem0 2.2.1 安装(hel857-venv 3.10.12)确定性替身实跑:tools/verify_mem0_real_hel874.py 12/12(零真实嵌入、零非回环连接、临时目录清理前逐笔账落盘);总管两复现脚本对本 checkout 复跑证据见交付评论附件",
|
||||
"tools/check_release_offline_hel882.py(echo 替身、随机回环端口、临时目录)全过;mem0 同进程导入缺项(3.11 无 wheel)如实记录,解决路径 deploy/hel874-release.md §4,本卡零下载",
|
||||
"python3 scripts/check_requirements.py --base-ref origin/main [--handoff docs/requirements/handoff-HEL-882.json] 与 --base-ref origin/agent/agent/de8874a3803b [--handoff …] 四项通过"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"baseline_version": "1.11",
|
||||
"read_commit": "59fb06304fb9f230837b43e431e2a1cc303e16c9",
|
||||
"task": "HEL-885 返工(总管对 HEL-882 59fb063 独立复审五项缺口的一次归拢修正):逐行恢复与真实来源一致(每次 add 只带自己那一行的锚点,向量只证明自身行;空提取行落 sem_row_done 完成证明;预算失败/崩溃重启/取消租约/并发不漏行、不伪完成、不重发完成行)、跨日结算按预占日记回原日并维护累计账(不再冲出新日负用量)、未知已发送预占永不超时退款(reserve 行唯一删除路径是可证明未发送的 release,llm/embed 同路径)、正 cap 必须验证权威来源(authority 缺/空/错在构造前 fail-closed,示例配置必填并给出 498已用+冻结2+新批增量的累计 cap/保留量算式)、发布依赖补齐命令改为本机确实支持的 python3 -m pip download 并入 R7 离线探针;零真实调用、零真实嵌入、零非回环出站、不部署、不合并、不改视觉、不碰权威三账",
|
||||
"requirement_ids": [
|
||||
"CG-006",
|
||||
"CG-008",
|
||||
"CG-011",
|
||||
"CG-013",
|
||||
"CG-014",
|
||||
"CG-015",
|
||||
"CG-016",
|
||||
"CG-021",
|
||||
"AM-001",
|
||||
"AM-002",
|
||||
"AM-003",
|
||||
"UX-004",
|
||||
"UX-006",
|
||||
"GOV-001",
|
||||
"GOV-002",
|
||||
"GOV-003",
|
||||
"GOV-005",
|
||||
"GOV-006",
|
||||
"DEL-001"
|
||||
],
|
||||
"deliverable": "在统一候选母线 hel-870-assembly(基于 59fb063 追加,PR#11 只追加不强推)上完成五项修正:1) 逐行进度与来源证明——Mem0Backend/StubBackend add_group 改为逐行发送、每次 add 的 metadata 只带该行锚点(turn_ids/turn_roles/input_sha256 均单行),向量存在只证明自身行;新增 sem_row_done 表(r4.sql 增量迁移)在每行 add 完成瞬间于 worker 线程内落持久完成记录(合法空提取=零向量也有完成证明),tick 恢复时以 向量库锚点∪sem_row_done 为跳过集,批次 entry_ids 跨部分尝试合并;吞错检测改逐行口径。2) 跨日账——PersistentBudget.settle/release 一律写 hold.day(token_usage/request_usage 按预占日,budget_total 全局),不再向 state.day 冲账制造负用量;另修 budget_total 空表时 total_requests_used/total_tokens_used 的 TypeError 崩溃(coalesce 子查询),旧用例靠该崩溃“通过”的假绿改为如实入账。3) 未知预占——_atomic_reserve 删除 1 小时过期 DELETE(reserve 行不再按龄清除),未知消费保守计费、跨重启保留,唯一删除路径是可证明未发送的显式 release();embed/llm 共用路径同修。4) 权威来源必填——Mem0Backend 在 import mem0 之前:任一 cap>0 而 authority 缺/空/非 dict 即抛 ledger_authority_required(构造前拒绝,不发任何请求),错的 authority 仍被 verify_ledger_authority 前缀校验拒绝;config/semantic.example.yaml authority 段改为必填示例并附累计算式(embed_cap=500+增量、embed_reserve=2、min_used=498,禁把 180 直接填成累计 cap、禁动旧冻结 2 条);docs/budget-plan-hel874.md §2 补同套算式与 HEL-885 记账口径。5) 发布命令——deploy/hel874-release.md §4 改为 python3 -m pip download(--only-binary :all: --platform manylinux2014_x86_64 --python-version 3.11 --implementation cp --abi cp311)+ sha256 留证 + uv pip install --no-index --find-links 离线并入 + 同进程 co-import 判据,如实列明本机无 3.11 wheel、本卡零下载、无包则如实上报不换版本;tools/check_release_offline_hel882.py 新增 R7 双探针(pip download 存在 rc=0、已删除的 uv pip download 保持不存在)。验证:3.11.16 venv+requirements.lock 离线 281 项 pytest 全过(新增 tests/test_rework_hel885.py 9 例:部分批次只认已发行/空提取不重发/进程重启只补缺行/并发 tick 不双发/跨日结算与释放按预占日/未知预占 llm+embed 不退款/缺空错 authority fail-closed;test_resume_never_loses_or_duplicates_rows 重写为真实产品路径,不再手工植入单行锚点),ruff 0 错(src/tests/tools),web tsc+42 vitest+build(npm ci --offline),固定 mem0 2.2.1 安装确定性替身:verify_mem0_real_hel874.py 12/12、新增 verify_semantic_recovery_hel885.py 7/7(S0 缺 authority 拒绝/S1 逐行部分/S2 重启只补缺行以 HTTP 计数证明/S3 租约回收+并发不双发/S4 未知预占不退款),总管 review_hel882_{partial,extra}.py 两脚本原样复跑全过(证据 docs/rework/hel885/),发布离线检查 R1–R7 全过;零真实调用、零真实嵌入、零非回环出站,权威三账与冻结余额未写,未部署未合并未交体验地址,不改视觉。",
|
||||
"acceptance": [
|
||||
"总管 partial 复现修复:首 tick 后 completed_message_ids=[2](仅伴侣行,向量逐行锚点),补 cap 后 done、entry_ids 2 条、回环 HTTP=2、用户原话确实发出且每行恰一次(manager-review-partial-rerun.json 原样脚本复跑)",
|
||||
"总管 extra 复现修复:跨日结算次日 used=0、估算 150 被拒、原日记实际 10;未知预占 second_allowed=false、used 保持 1(manager-review-extra-rerun.json 原样脚本复跑)",
|
||||
"逐行恢复真实产品路径:空提取行有 sem_row_done 完成证明且不再重发;进程重启后只补缺行;并发 tick 不双发(tests/test_rework_hel885.py + recovery-real-sdk.json S1–S3)",
|
||||
"未知预占保守计费:llm_ops 与 embed_ops 同路径,一小时前的未结算预占跨重启仍占额度,唯一删除路径是显式可证明未发送的 release(S4a/S4b + 对应用例)",
|
||||
"authority 必填:缺/空/错 authority 在构造前拒绝(ledger_authority_required / 前缀不匹配),示例配置必填并附 500+增量、reserve=2、min_used=498 算式,明确禁把 180 填成累计 cap、禁动旧冻结 2 条(tests + recovery-real-sdk.json S0 + semantic.example.yaml + budget-plan-hel874.md)",
|
||||
"发布命令真实可用:§4 改为 python3 -m pip download(本机实测 rc=0),R7 双探针入离线检查;本机无 3.11 wheel、零下载、缺包如实上报的口径不变(release-offline-hel885.json)",
|
||||
"工程检查:281 pytest、ruff 0(src/tests/tools)、web typecheck/42 vitest/build、双目标需求检查 4/4(含本 handoff);固定 SDK 合同 12/12 复跑通过"
|
||||
],
|
||||
"deferred": [
|
||||
"发布与体验地址:由总管独立复审本 head 后交发布卡按 deploy/hel874-release.md 执行(8360 隔离实例);本卡未部署未合并 PR#11 未交体验地址",
|
||||
"真实语义激活(CYBERGRIL_SEMANTIC=mem0):需 B 部分预算批准 + 3.11 mem0 栈 wheel 落位(按 §4 新命令执行并留 sha256 证);未激活前 stub/FTS 不冒充真实记忆体验",
|
||||
"A/B/C 执行表数值仍为待批建议:批准前所有 cap 保持 0=拒绝;authority 前缀实际值由总管按权威账现状填写;新增预算由总管向白栖知一次性申请",
|
||||
"R5 语音/R6 天气、素材、备份/R7 有条件观察承接不变;视觉仍交原作者,本卡未改视觉",
|
||||
"真实体验效果待体验地址交付后由白栖知判断"
|
||||
],
|
||||
"requirement_changes": [],
|
||||
"verification": [
|
||||
"分支 hel-870-assembly 追加提交(最终 head 见交付评论),PR#11 只追加未强推未合并;视觉总监分支未覆盖",
|
||||
"python 3.11.16 venv + requirements.lock 离线:281 项测试全过(新增 tests/test_rework_hel885.py 9 例,重写 test_resume_never_loses_or_duplicates_rows);ruff 0 错(src/tests/tools);web typecheck/vitest 42/build 通过(npm ci --offline)",
|
||||
"固定 mem0 2.2.1 安装(hel857-venv 3.10.12)确定性替身实跑:tools/verify_mem0_real_hel874.py 12/12;新增 tools/verify_semantic_recovery_hel885.py 7/7(零真实嵌入、零非回环);总管 review_hel882_{partial,extra}.py 原样复跑证据 docs/rework/hel885/manager-review-{partial,extra}-rerun.json",
|
||||
"tools/check_release_offline_hel882.py(echo 替身、随机回环端口、临时目录)R1–R7 全过;mem0 同进程导入缺项(3.11 无 wheel)如实记录,解决路径 deploy/hel874-release.md §4 新命令,本卡零下载",
|
||||
"python3 scripts/check_requirements.py --base-ref origin/main [--handoff docs/requirements/handoff-HEL-885.json] 与 --base-ref origin/agent/agent/de8874a3803b [--handoff …] 四项通过"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
{
|
||||
"baseline_version": "1.11",
|
||||
"read_commit": "78b6267d3a9cc9adc1136fc4bf22c4178a38cab2",
|
||||
"task": "HEL-886 返工(总管对 HEL-885 候选 78b6267 独立复审确认的两个缺口一次修完):处理中取消与租约回收不得把仍在运行的真实 worker 当死亡而双发同一行(总管实际固定 SDK 复现:取消只取消等待协程、to_thread 中 HTTP 仍在跑时 finally 立即 failed/清 owner,第二 tick 重领并发第二 HTTP;不取消、注入时钟前进 41 秒 recover 同样回收活 worker 重发;两例同一句 2 HTTP/2 向量而批 done 只记 1 entry)、已全完成批次无新余额也须可收尾(总管第三例:llm_cap=1 单行已真实完成,落『行完成已持久、批状态未写』过期 pending 后重启,add_group 在计算 skip 前先 check(1) 导致全完成仍 queued/budget_exhausted);零真实调用、零真实嵌入、零非回环出站、不部署、不合并、不改视觉、不碰权威三账、不新增任何 cap",
|
||||
"requirement_ids": [
|
||||
"CG-006",
|
||||
"CG-008",
|
||||
"CG-011",
|
||||
"CG-013",
|
||||
"CG-014",
|
||||
"CG-015",
|
||||
"CG-016",
|
||||
"CG-021",
|
||||
"AM-001",
|
||||
"AM-002",
|
||||
"AM-003",
|
||||
"UX-004",
|
||||
"UX-006",
|
||||
"GOV-001",
|
||||
"GOV-002",
|
||||
"GOV-003",
|
||||
"GOV-005",
|
||||
"GOV-006",
|
||||
"DEL-001"
|
||||
],
|
||||
"deliverable": "在统一候选母线 hel-870-assembly(基于 78b6267 追加,PR#11 只追加不强推)完成两项修正:1) 活跃 worker 生命周期——SemanticMemory 增进程内活跃注册表(batch_id→_LiveWorker,登记先于线程启动);批次的行构建/续跑集/真实 add/终态写入全部移入 worker 线程函数 _run(Mem0Backend/StubBackend 抽出同步核心 _add_group_sync,add_group 保持异步合同仅包装);取消等待协程不再触碰批次状态(旧缺陷:finally 把活跃批次写成 failed 供重领);recover() 只回收无活跃 worker 的过期 pending(真死 owner 语义保持保守:结果未知、预占不退、重试只发无证明行、不宣称严格一次);并发 tick 对活跃批次不可领不重发;新增 SemanticMemory.aclose() 排空仍运行 worker 后才关 backend,app lifespan 改走该路径先排空再关 store。2) 完成证明先于预算闸——_add_group_sync 先算 完成集(向量锚点∪sem_row_done)∩剩余工作,全完成零新 HTTP/嵌入即返回完成(重启收尾 done、entry_ids 跨尝试完整、cap 不变不退款);仍有缺行时维持 ledger/llm_guard 原硬闸 fail-closed。验证:3.11.16 venv+requirements.lock 离线 287 pytest 全过(新增 tests/test_rework_hel886.py 6 例:处理中取消不双发/跨租约仍活跃不回收+并发 tick 不重发/真死 owner 租约照常回收/关闭排空先于关库/全完成零新预算收尾/部分未完成仍硬闸拒绝,全部用屏障阻塞的真实产品路径驱动,不再用预置死租约或快任务并发冒充),ruff 0 错(src/tests/tools),固定 mem0 2.2.1 确定性替身:总管 review_hel885_inflight.py 原样复跑在 2-add 屏障处如预期断言失败(修复前该屏障通过且 2 HTTP/2 向量——双发已消失,唯一调整是把屏障改为 1 次完成的同形脚本 review_hel886_inflight_rerun.py:两场景 1 HTTP/1 向量/1 sem_row_done、飞行中批次保持 pending、终态 done 且 entry_ids 完整;第三例重启后 done、零新 HTTP、llm_used 仍 1、entry_ids 原样);新增 tools/verify_inflight_lifecycle_hel886.py 6/6(L1 取消单发全记录/L2 跨租约活跃不重发/L3 关闭排空先于关库/L4a 全完成零新预算收尾/L4b 缺行仍硬闸/L5 真死租约照常回收);verify_semantic_recovery_hel885.py 7/7、verify_mem0_real_hel874.py 12/12、check_release_offline_hel882.py R1–R7 15/15、总管 review_hel882_{partial,extra}.py 原样复跑全过;零真实调用、零真实嵌入、零非回环出站,权威三账与冻结余额未写,未部署未合并未交体验地址,不改视觉。",
|
||||
"acceptance": [
|
||||
"总管 inflight 复现修复(取消例):第一 HTTP 已接受未返回时取消 tick,批次保持 pending/owner 不被写 failed;并发第二/三 tick 不重发;worker 完成后 1 HTTP、1 向量、1 条 sem_row_done,批 done 且 entry_ids 与行记录一致(docs/rework/hel886/HEL-886-inflight-rerun.json + inflight-real-sdk.json L1)",
|
||||
"总管 inflight 复现修复(租约例):注入时钟前进 41 秒、worker 仍在第一请求中,recover 不回收活跃批次,并发 tick 不重发;最终同样 1 HTTP/1 向量/1 行记录(L2)",
|
||||
"晚到写入不漏记:飞行中批次不被重领,最终 entry_ids 与 sem_row_done 完整一致,无重复向量、无漏记完成条目(两场景 JSON)",
|
||||
"关闭先排空:aclose 等待仍运行 worker 的持久写落盘后才关向量库 client(L3:排空期间完成的行 done_at/finished_at 证明写在 aclose 开始之后)",
|
||||
"总管第三例修复:llm_cap=1 已用完且单行已真实完成,重启后零新 HTTP、cap 不变即 done、entry_ids 原样;部分未完成仍按原硬闸拒绝(L4a/L4b + tests/test_rework_hel886.py)",
|
||||
"真死进程恢复语义未停用:无活跃 worker 的过期 pending 照常 failed/lease_expired 并重试缺行;未知预占不退款口径不变(L5 + S4a/S4b 复跑)",
|
||||
"工程检查:287 pytest(含 6 新例)、ruff 0(src/tests/tools)、web typecheck/42 vitest/build、双目标需求检查 4/4(含本 handoff);固定 SDK 合同 12/12、HEL-885 恢复 7/7、发布离线 R1–R7 15/15、总管两脚本原样复跑通过"
|
||||
],
|
||||
"deferred": [
|
||||
"发布与体验地址:由总管独立复审本 head 后交发布卡按 deploy/hel874-release.md 执行(8360 隔离实例);本卡未部署未合并 PR#11 未交体验地址",
|
||||
"真实语义激活(CYBERGRIL_SEMANTIC=mem0):需 B 部分预算批准 + 3.11 mem0 栈 wheel 落位;未激活前 stub/FTS 不冒充真实记忆体验",
|
||||
"A/B/C 执行表数值仍为待批建议:批准前所有 cap 保持 0=拒绝;新增预算由总管统一处理,不作为本卡离线修复阻塞",
|
||||
"真死进程『严格一次』不在本卡宣称范围:远端无幂等支持时崩溃结果未知,恢复保守留账、只发无证明行(运行手册 §4 已如实写明)",
|
||||
"R5 语音/R6 天气、素材、备份/R7 有条件观察承接不变;视觉仍交原作者,本卡未改视觉;真实体验效果待体验地址交付后由白栖知判断"
|
||||
],
|
||||
"requirement_changes": [],
|
||||
"verification": [
|
||||
"分支 hel-870-assembly 追加提交(最终 head 见交付评论),PR#11 只追加未强推未合并;视觉总监分支未覆盖",
|
||||
"python 3.11.16 venv + requirements.lock 离线:287 项测试全过(新增 tests/test_rework_hel886.py 6 例,全部屏障阻塞真实产品路径);ruff 0 错(src/tests/tools);web typecheck/vitest 42/build 通过(npm ci --offline)",
|
||||
"固定 mem0 2.2.1 安装(hel857-venv 3.10.12)确定性替身实跑(docs/rework/hel886/):总管 review_hel885_inflight.py 原样复跑在 worker_done 2-add 屏障断言失败(original-verbatim-after-fix.log,修复前基线 HEL-885-inflight-baseline-78b6267.json 为 2 HTTP/2 向量);调整屏障为 1 的同形脚本 review_hel886_inflight_rerun.py 全过(HEL-886-inflight-rerun.json);新增 tools/verify_inflight_lifecycle_hel886.py 6/6(inflight-real-sdk.json)",
|
||||
"回归:tools/verify_semantic_recovery_hel885.py 7/7、tools/verify_mem0_real_hel874.py 12/12、tools/check_release_offline_hel882.py R1–R7 15/15、总管 review_hel882_{partial,extra}.py 原样复跑通过(docs/rework/hel886/)",
|
||||
"python3 scripts/check_requirements.py --base-ref origin/main [--handoff docs/requirements/handoff-HEL-886.json] 与 --base-ref origin/agent/agent/de8874a3803b [--handoff …] 四项通过"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
{
|
||||
"baseline_version": "1.11",
|
||||
"read_commit": "f1b50ad91ad8c856f28383ee59eddb6547d9c586",
|
||||
"task": "HEL-889 返工(总管对 HEL-886 候选 f1b50ad 独立复审确认的两个生命周期边界缺口一次修完):关闭超时不得把仍可能写入的活 worker 当死而关掉其依赖(总管实际固定 SDK 复现:回环网关先接受第一 HTTP 未答,aclose(drain_timeout=0.05) 返回时 worker 仍活,按 app 顺序关 Store 后放行,Qdrant 报 QdrantLocal instance is closed、worker 报 ProgrammingError: Cannot operate on a closed database,重开批次仍 pending/row_done=0/llm_used=1——仍活进程主动关资源造成的丢落盘窗口,不能归入真崩溃结果未知)、执行器排队阶段取消不得永久假活跃(先登记 _live 再 await to_thread,执行器忙时取消 tick 会取消排队 future,_run/finally 从未运行,注册表留下不存在的 worker,批次 pending 卡死且之后恢复一直跳过,只能重启;单 worker 执行器+41 秒时钟前进+recover+tick 复现 _live=1/entries=0/row_done=0/队列空);零真实调用、零真实嵌入、零下载、不部署、不合并、不改视觉、不碰权威三账、不新增任何 cap、不改运行时/模型/认证",
|
||||
"requirement_ids": [
|
||||
"CG-006",
|
||||
"CG-008",
|
||||
"CG-011",
|
||||
"CG-013",
|
||||
"CG-014",
|
||||
"CG-015",
|
||||
"CG-016",
|
||||
"CG-018",
|
||||
"CG-021",
|
||||
"AM-001",
|
||||
"AM-002",
|
||||
"AM-003",
|
||||
"UX-004",
|
||||
"UX-006",
|
||||
"GOV-001",
|
||||
"GOV-002",
|
||||
"GOV-003",
|
||||
"GOV-004",
|
||||
"GOV-005",
|
||||
"GOV-006",
|
||||
"DEL-001"
|
||||
],
|
||||
"deliverable": "在统一候选母线 hel-870-assembly(基于 f1b50ad 追加,PR#11 只追加不强推不合并)完成两项修正:1) 关闭所有权协议——批 worker 移入 SemanticMemory 专用执行器(本层持有 concurrent.futures.Future,即权威的排队/已启动判定,且长批次不再挤占 loop 共享默认执行器);aclose 先置 closing 信号:tick 拒新领、后端 _add_group_sync 在每行发送前查 should_stop 只在行边界中止(已完行保留 sem_row_done 证明,未发行回 queued,绝无在飞中断)、未启动 worker 直接按 CANCELLED 权威取消(从未运行=零出站,安全回队并复原 attempts);随后等待所有活跃 worker 真实退出才关 backend 与执行器——drain_timeout 只界定礼貌阶段(超时如实告警并继续等,绝不把活 worker 当死),Mem0Backend 构造时给网关 OpenAI 客户端设 gateway_timeout(默认 60s,可配)保证排空有界;aclose 被取消时什么都不关且 closing 复位可续用,并发 aclose 用 asyncio.Lock 串行化且幂等,完成端关闭 asyncio.shield 保护;真崩溃语义不变(保守留账、只发无证明行、不宣称严格一次)。2) 排队取消恢复——_LiveWorker 增加 started 事件与 future 槽位区分排队/已启动/已完成;取消等待协程时以 future.cancelled() 权威判定:从未运行则立即释放假活跃注册项并回队(attempts 复原、零发送),释放执行器、时钟前进 41 秒后 recover+tick 进程内完成,无需重启;已开始/已完成则维持 HEL-886 语义(worker 线程写终态、并发 tick 不重发,不回到双发)。保留全部已通过行为(回读、隐私、单行恢复、预算硬闸、未知预占不退款、全完成零预算收尾)。app lifespan 注释同步为 HEL-889 所有权口径。验证:python 3.11.16 venv + requirements.lock 离线 294 pytest 全过(新增 tests/test_rework_hel889.py 7 例,全部屏障驱动真实产品路径:排队取消恢复/关闭超时不关活 worker 且落盘先于关库/行间中止下一进程只发缺行/未启动即关闭零发送并可续跑/关闭被取消什么都不关/并发关闭串行化/关闭后拒新领),ruff 0 错(src/tests/tools);固定 mem0 2.2.1 确定性替身实跑 tools/verify_shutdown_queued_hel889.py 12/12(Q1 排队取消、S1 关闭超时分支固定 SDK 实跑、S2 行间中止、S3 关闭被取消、S4 并发关闭);总管 review_hel886_edges.py 原负例与基线保留(edges-verbatim-before-fix-f1b50ad.json 与总管独立结果一致),同形复跑 review_hel886_edges_rerun_hel889.py 全过(queued:done/attempts=1/registered 0/entries 1/row_done 1;timeout:aclose_returned_while_worker_alive=false/late_worker_error=null/persisted done+entry_ids+row_done=1/llm_used=1),原样复跑如实停在其自身前提断言(批 worker 不再走 loop 默认执行器,docs/rework/hel889/original-verbatim-after-fix.log);回归 verify_inflight_lifecycle_hel886.py 6/6、verify_semantic_recovery_hel885.py 7/7、verify_mem0_real_hel874.py 12/12、check_release_offline_hel882.py R1–R7 15/15、总管 review_hel882_{partial,extra}.py 原样复跑通过、review_hel885_inflight.py 仍在 2-add 屏障如预期失败(单发保持);零真实调用、零真实嵌入、零非回环出站,权威三账与冻结余额未写,未部署未合并未交体验地址,不改视觉",
|
||||
"acceptance": [
|
||||
"P1 修复(固定 SDK 实跑关闭超时分支):第一 HTTP 已接受未答时 aclose(drain_timeout=0.05) 在 worker 仍活时绝不返回;应答放行后 worker 完成落盘,aclose 才返回、才关 client;按 app 顺序关库重开:批 done、row_done=1、entry_ids 完整、llm_used=1、无任何晚到错误(docs/rework/hel889/edges-real-sdk-hel889.json S1 + HEL-889-edges-rerun-fixed.json shutdown_timeout;修复前基线 aclose_returned_while_worker_alive=true/ProgrammingError/pending/row_done=0 保留对照)",
|
||||
"P1 关闭取消/并发:排空中的 aclose 被取消什么都不关(client 可用、批次仍 pending、closing 复位可续用),worker 正常完成后再次 aclose 干净收尾;两个 aclose 并发串行化、排空一次、资源只关一次、第三次调用幂等即返(S3/S4 + tests/test_rework_hel889.py)",
|
||||
"P2 修复(排队取消):单 worker 执行器占住、批次仅入队未启动即取消 tick——假活跃注册项立即释放、批次回 queued 且 attempts 复原、零出站;释放执行器、推进 41 秒后 recover+tick 进程内完成:done、1 条目、1 sem_row_done、注册表清零,无需重启(Q1 + 同形复跑 queued_cancel;修复前基线 pending/_live=1/entries=0/row_done=0 保留对照)",
|
||||
"已开始取消仍单发:处理中取消/跨租约仍活跃不重发不回收(HEL-886 L1/L2 回归 6/6),review_hel885_inflight.py 仍在 2-add 屏障如预期失败,未回退双发",
|
||||
"行间中止与恢复:两行批次关闭中止保留第 1 行完成证明、批次回 queued/shutdown_between_rows、关闭期间网关 POST 不新增;下一进程同账同库只发缺行(POST 仅 +1)后 done 且两行 entry_ids 完整(S2 + pytest)",
|
||||
"原有能力全部保留:回读/隐私/单行恢复/预算硬闸/未知预占不退款/全完成零预算收尾/真死租约回收(recovery-hel885-rerun 7/7、inflight-hel886-rerun 6/6、contract-hel874-rerun 12/12、release-offline R1–R7 15/15、总管 882 两脚本原样复跑通过)",
|
||||
"工程检查:294 pytest(含 7 新例)全过、ruff 0 错(src/tests/tools);本卡不改前端,未重跑前端 42 项/构建,不以历史数字冒充本轮实测;双目标需求检查 4/4(含本 handoff)"
|
||||
],
|
||||
"deferred": [
|
||||
"发布与体验地址:由总管独立复审本 head 后交发布卡按 deploy/hel874-release.md 执行(8360 隔离实例);本卡未部署未合并 PR#11 未交体验地址",
|
||||
"真实语义激活(CYBERGRIL_SEMANTIC=mem0):需 B 部分预算批准 + 3.11 mem0 栈 wheel 落位;未激活前 stub/FTS 不冒充真实记忆体验",
|
||||
"A/B/C 执行表数值仍待批建议:批准前所有 cap 保持 0=拒绝;新增预算由总管统一处理,不作为本卡阻塞",
|
||||
"真死进程『严格一次』不在本卡宣称范围:远端无幂等支持时崩溃结果未知,恢复保守留账、只发无证明行(runbook §4 HEL-889 段已如实写明)",
|
||||
"R5 语音 HEL-878/879、R6 天气/素材/完整备份、R7 有条件观察承接不变;视觉仍交原作者,本卡未改视觉;真实体验效果待体验地址交付后由白栖知判断"
|
||||
],
|
||||
"requirement_changes": [],
|
||||
"verification": [
|
||||
"分支 hel-870-assembly 追加提交(最终 head 见交付评论),PR#11 只追加未强推未合并;视觉总监分支未覆盖",
|
||||
"python 3.11.16 venv + requirements.lock 离线:294 项测试全过(新增 tests/test_rework_hel889.py 7 例,全部屏障驱动真实产品路径,无预置死租约冒充);ruff 0 错(src/tests/tools);本卡未改前端故未重跑前端检查,如实注明",
|
||||
"固定 mem0 2.2.1 安装(hel857-venv 3.10.12)确定性替身实跑(docs/rework/hel889/):tools/verify_shutdown_queued_hel889.py 12/12(edges-real-sdk-hel889.json);总管脚本基线原样复跑 edges-verbatim-before-fix-f1b50ad.json 与总管独立结果一致;同形复跑 review_hel886_edges_rerun_hel889.py 全过(HEL-889-edges-rerun-fixed.json);原样复跑停在其自身前提断言(original-verbatim-after-fix.log,原负例与基线不删)",
|
||||
"回归:verify_inflight_lifecycle_hel886.py 6/6、verify_semantic_recovery_hel885.py 7/7、verify_mem0_real_hel874.py 12/12、check_release_offline_hel882.py R1–R7 15/15、总管 review_hel882_{partial,extra}.py 原样复跑通过;review_hel885_inflight.py 原样复跑仍在 2-add 屏障如预期失败(单发保持,与 HEL-886 存档口径一致)",
|
||||
"python3 scripts/check_requirements.py --base-ref origin/main [--handoff docs/requirements/handoff-HEL-889.json] 与 --base-ref origin/agent/agent/de8874a3803b [--handoff …] 四项通过"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
{
|
||||
"baseline_version": "1.11",
|
||||
"read_commit": "ceb0f35418f0d0b28b4e2a359615194db8eb4567",
|
||||
"task": "HEL-894 返工(总管对 HEL-889 head ceb0f35 独立复审确认的关闭取消两处组合漏洞一次修完):关闭提交阶段被取消仍须保持关闭所有权——semantic.py 原实现 shield(_finish()) 让内部关闭在后台继续,却向外抛取消、释放锁并清 closing,层次被误报可续用,新 tick 把批次领进即将消失的资源(总管实际固定 SDK 屏障复现:取消返回 closing=false/closed=false/client 可用 → 新批 HTTP 已接受未答 → 旧 _finish 关 Qdrant → 不关 Store 也 failed/row_done=0/llm_used=1(QdrantLocal instance is closed);调用方随后关 Store 则晚到 ProgrammingError,重开 pending/row_done=0);取消等锁者不得修改持锁关闭者状态——第二 aclose 等锁即取消,外层 except 清掉第一关闭者的 closing(固定 SDK 复现第一 close 仍 pending 但 signal=false,原 worker 未放行时新批已 done)。零真实调用、零真实嵌入、零下载、不部署、不合并、不改视觉、不碰权威三账、不变真实 cap 与冻结余额、不改运行时/模型/认证",
|
||||
"requirement_ids": [
|
||||
"CG-006",
|
||||
"CG-008",
|
||||
"CG-011",
|
||||
"CG-013",
|
||||
"CG-014",
|
||||
"CG-015",
|
||||
"CG-016",
|
||||
"CG-018",
|
||||
"CG-021",
|
||||
"AM-001",
|
||||
"AM-002",
|
||||
"AM-003",
|
||||
"UX-004",
|
||||
"UX-006",
|
||||
"GOV-001",
|
||||
"GOV-002",
|
||||
"GOV-003",
|
||||
"GOV-004",
|
||||
"GOV-005",
|
||||
"GOV-006",
|
||||
"DEL-001"
|
||||
],
|
||||
"deliverable": "在统一候选母线 hel-870-assembly(基于 ceb0f35 正常追加,PR#11 只追加不强推不合并)完成两项修正:1) 两阶段取消语义——aclose 明确排空可撤销阶段(尚未关任何资源:取消什么都不关、closing 复位、层次可续用,保持 HEL-889 行为)与提交不可逆阶段(backend.aclose 已开始:被取消的调用方不清 closing、不放行 tick(半关闭绝不宣称可用)、不释放锁,等待自己启动的层持有关闭任务(_close_task,asyncio.create_task 创建恰一次、存于本层从不丢到后台、重复取消只重新 shield 同一任务)落成后才传播 CancelledError,资源恰关一次;_finish_close 里本层自有执行器 shutdown 改走 asyncio.to_thread,取消方不可能以同步 join 阻塞事件循环;调用方注入执行器仍由调用方持有,与总管脚本口径一致)。2) 所有权最小化——aclose 增加 owns_close 判定:只有真正取得 _aclose_lock 并置位 closing 的调用才可在仍可撤销(无 _close_task)时复位信号;等锁被取消的调用不改变持锁关闭者的任何状态。模块 docstring、aclose docstring、app lifespan 注释同步新协议口径。真崩溃语义不变(保守留账、只发无证明行、不宣称严格一次)。验证:python 3.11.16 venv + requirements.lock 离线 299 pytest 全过(新增 tests/test_rework_hel894.py 5 例,全部屏障驱动真实产品路径:提交阶段取消保持所有权并拒新工作零发送零计费/重复取消仍一次落成/同阶段第二调用等待后幂等返回且第三个等锁者取消不动状态/等锁者取消+持锁排空+新批 tick 拒绝+原 worker 完成组合/排空阶段取消仍可续用续跑),ruff 0 错(src/tests/tools);固定 mem0 2.2.1 确定性替身实跑 tools/verify_close_ownership_hel894.py 16/16(总管两负例同形:F1 提交取消 SDK-only——取消后 closing=true/closed=false/client 可用、取消方等关闭落成才返回、新批 tick 被拒(网关零到达、queued/owner NULL/attempts 0、llm_used=0)、放行后关闭恰一次、重开批次 queued 完好/row_done=0/llm_used=0;F2 +Store 关闭分支同形且无晚到错误;W 等锁者取消——closing 保持、新批 queued、原 worker 放行后 done/row_done=1、一次收尾);总管脚本原件在未改动 ceb0f35 上原样复跑基线与总管独立结果一致(before-ceb0f35.json),修复后原样复跑如实停在其自身前提断言 server.arrived(新协议下 tick 拒新领,前提结构性移除,verbatim-after-fix.log,原负例与基线保留不删);回归 verify_shutdown_queued_hel889.py 12/12、verify_inflight_lifecycle_hel886.py 6/6、verify_semantic_recovery_hel885.py 7/7、verify_mem0_real_hel874.py 12/12、check_release_offline_hel882.py R1–R7 15/15、总管 review_hel882_{partial,extra}.py 原样复跑通过、HEL-889 同形复跑通过;零真实 LLM/真实嵌入/非回环出站,权威三账与冻结余额未写,未部署未合并未交体验地址,不改视觉",
|
||||
"acceptance": [
|
||||
"负例一修复(固定 SDK 实跑,SDK-only 分支):真实 client.close 进入后取消 aclose——取消返回时 closing=true/closed=false/client 可用(不再宣称可续用);新批 tick 被拒:网关零到达、批次 queued/owner NULL/attempts 0、llm_used=0(修复前:closing=false + 新批被领 + QdrantLocal instance is closed + failed/row_done=0/llm_used=1);被取消调用方等层持有关闭任务落成后才传播(closed=true/client 不可用/live_workers=0/close 恰一次);重开批次 queued 完好、row_done=0、llm_used=0",
|
||||
"负例一加强分支(调用方随后关 Store,单独记录不与 SDK-only 混淆):同上且无任何晚到错误(修复前 ProgrammingError: Cannot operate on a closed database,重开 pending/row_done=0/llm_used=1)",
|
||||
"负例二修复(固定 SDK 实跑):第一 aclose 排空中、第二等锁即取消——closing 保持置位(修复前被清);新批 tick 被拒仍 queued;原 worker 放行后 done/row_done=1;第一关闭随后一次收尾关库;新批保持 queued",
|
||||
"所有权完整回归(pytest 屏障驱动真实路径):排空取消可续用(closing 复位、后续批次正常跑完)、提交阶段取消不得半关可用、同阶段第二调用等待后幂等且一次关闭、重复取消仍一次落成、等锁者取消不动状态、并发关闭一次(HEL-889 既有用例保持全绿)、成功关闭拒新任务;原排队取消、活 worker 超时排空、行间续跑、处理中取消单发、全完成零预算收尾全部保持(299 pytest、shutdown-queued 12/12、inflight 6/6、recovery 7/7、contract 12/12、release R1–R7 15/15)",
|
||||
"总管脚本原件保留:未改动 ceb0f35 上原样复跑基线与总管独立 JSON 一致(before-ceb0f35.json);修复后原样复跑停在其自身前提断言并如实存档(verbatim-after-fix.log);同形重跑断言按新安全协议改写并逐条注明(tools/verify_close_ownership_hel894.py,close-ownership-real-sdk.json 16/16)",
|
||||
"工程检查:299 pytest(含 5 新例)全过、ruff 0 错(src/tests/tools);本卡未改前端、未重跑前端检查、不冒充历史数字;双目标需求检查 4/4(含本 handoff)"
|
||||
],
|
||||
"deferred": [
|
||||
"发布与体验地址:由总管独立复审本 head 后交发布卡按 deploy/hel874-release.md 执行(8360 隔离实例);本卡未部署未合并 PR#11 未交体验地址",
|
||||
"真实语义激活(CYBERGRIL_SEMANTIC=mem0):需 B 部分预算批准 + 3.11 mem0 栈 wheel 落位;未激活前 stub/FTS 不冒充真实记忆体验",
|
||||
"A/B/C 执行表数值仍待批准建议:批准前所有 cap 保持 0=拒绝;新增预算由总管统一处理,不作为离线修复阻塞",
|
||||
"真死进程『严格一次』不在宣称范围:远端无幂等支持时崩溃结果未知,恢复保守留账、只发无证明行(runbook §4 HEL-889/894 段已如实写明)",
|
||||
"R5 语音 HEL-878/879、R6 天气/素材/完整备份、R7 有条件观察承接不变;视觉仍交原作者,本卡未改视觉;真实体验效果待体验地址交付后由白栖知判断"
|
||||
],
|
||||
"requirement_changes": [],
|
||||
"verification": [
|
||||
"分支 hel-870-assembly 追加提交(最终 head 见交付评论),PR#11 只追加未强推未合并;视觉总监分支未覆盖",
|
||||
"python 3.11.16 venv + requirements.lock 离线:299 项测试全过(新增 tests/test_rework_hel894.py 5 例,全部屏障驱动真实产品路径,无预置死租约冒充活线程);ruff 0 错(src/tests/tools);本卡未改前端故未重跑前端检查,如实注明",
|
||||
"固定 mem0 2.2.1 安装(hel857-venv 3.10.12)确定性替身实跑(docs/rework/hel894/):tools/verify_close_ownership_hel894.py 16/16(close-ownership-real-sdk.json,F1/F2/W 为总管两负例同形重跑,断言按新协议改写并注明);总管脚本基线原样复跑与独立结果一致(before-ceb0f35.json);修复后原样复跑停在自身前提断言(verbatim-after-fix.log)",
|
||||
"回归:verify_shutdown_queued_hel889.py 12/12、verify_inflight_lifecycle_hel886.py 6/6、verify_semantic_recovery_hel885.py 7/7、verify_mem0_real_hel874.py 12/12、check_release_offline_hel882.py R1–R7 15/15、总管 review_hel882_{partial,extra}.py 原样复跑通过、HEL-889 同形复跑(review_hel886_edges_rerun_hel889.py)通过;review_hel885_inflight.py 本轮未重跑,其存档口径不变",
|
||||
"python3 scripts/check_requirements.py --base-ref origin/main [--handoff docs/requirements/handoff-HEL-894.json] 与 --base-ref origin/agent/agent/de8874a3803b [--handoff …] 四项通过"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
{
|
||||
"baseline_version": "1.11",
|
||||
"read_commit": "152479b3503c3d1ab27681170e6bfd592c54380a",
|
||||
"task": "HEL-895 发布准备:把 HEL-894 已过独立复审的统一内核(152479b)与 HEL-881 已审核的主动留言前端原稿(bf234570,原作者六文件逐字、CSS 零改动)机械装成同一可审核可执行的统一发布候选。先核对包含关系(bf234570 不是 152479b 的祖先;母线 31970c4..152479b 从未触碰 web/),以正常合并带入恰两个提交共 9 个文件,src/tests/tools/config 相对 152479b 逐字不变,全部 HEL-874..894 后端修复保留;不重设计、不做视觉决定、不覆盖视觉分支,旧 b48d28b 测试合并未推送由本候选取代。零真实 LLM、零真实嵌入、零新增下载、不部署、不合并 PR、不交体验地址、不触 8300–8350 与共享语音口型、不访问 4080、不导入演示测试档案为用户伴侣、不写权威账、不变真实 cap、不改运行时/模型/认证",
|
||||
"requirement_ids": [
|
||||
"CG-006",
|
||||
"CG-008",
|
||||
"CG-009",
|
||||
"CG-010",
|
||||
"CG-011",
|
||||
"CG-012",
|
||||
"CG-013",
|
||||
"CG-014",
|
||||
"CG-015",
|
||||
"CG-016",
|
||||
"CG-018",
|
||||
"CG-021",
|
||||
"CG-023",
|
||||
"CG-029",
|
||||
"CG-030",
|
||||
"CG-031",
|
||||
"VIS-013",
|
||||
"AM-001",
|
||||
"AM-002",
|
||||
"AM-003",
|
||||
"UX-001",
|
||||
"UX-005",
|
||||
"UX-006",
|
||||
"GOV-001",
|
||||
"GOV-002",
|
||||
"GOV-003",
|
||||
"GOV-004",
|
||||
"GOV-005",
|
||||
"GOV-006",
|
||||
"DEL-001"
|
||||
],
|
||||
"deliverable": "统一发布候选(分支 hel-870-assembly 正常追加,精确 head 见交付评论,PR#11 只追加不强推不合并):1) 机械整合合并提交——第一父 152479b、合入 bf234570,仅新增原作者前端六文件(web/src/adapters/inbox.ts、real.ts、app/RealApp.tsx、chat/ChatPanel.tsx 与三个测试)+ handoff-HEL-875/880.json,web/ 逐字等于 bf234570、src/tests/tools/config 逐字等于 152479b;2) 合成后全量验证在本 head 实跑:python 3.11.16 venv + requirements.lock 离线 299 pytest 全过、ruff 0 错;web typecheck 0 错、lint 0 错(1 条既有警告非本卡)、vitest 55/55、build 通过且 CSS 仍 index-DdDYzR5S.css(视觉零改动);固定 SDK(hel857-venv 3.10.12,未混 site-packages)确定性 512 维替身 + 仅回环实跑:关闭所有权 16/16、关闭排队 12/12、处理中生命周期 6/6、语义恢复 7/7、真实接线 12/12、发布离线检查 15/15;3) 新增并实跑两项本卡验证:真实 HTTP 分页合同 7/7(tools/verify_http_pagination_hel895.py——真实产品服务、327 行播种、倒序+limit+1 探测+next_before+epoch 合同、公开字段允许清单与 proactive 标记恰在播种行、inbox.ts fetchAfter 缺口游标的机械移植对真实后端复验:一次调用最多 5 页缺口保留、下次补齐按 id 序恰好交出两条新留言不跳不重);真实服务浏览器 7/7(web/tests/hel895_real.mjs——Chromium CDP 对真实 API + web/dist:真实启动、留言卡过真实 HTTP 到达、舞台播放、260 行在其上的长缺口语义(HEL-880 回归)真实服务复验不跳留言且无重复、服务重启 epoch+1 后同批行不加第二次、零权限申请),证据 docs/rework/hel895/;4) 发布包与清单 deploy/hel895-release-candidate.md(精确 head、交付物清单、安装引用、健康矩阵、停用回退、固定 SDK 3.11 准确缺项);5) 一次可批准预算执行包 docs/budget-package-hel895.md(A 55 请求/500000 tokens/0 嵌入一次性、B 60 提取 LLM/180 嵌入按 500+180 算式、C 逐类日顶;逐笔发送前四道闸叠加口径、交叉=有意叠加、无重复、无漏记、失败取消保守入账不退款、碰顶停机与留证;默认全 0 不变,冻结 39/60 与 498/500 及 HEL-835 闸原样保全);6) 本地离线核实 3.11 固定 SDK 现状:产品 venv 无 mem0/qdrant_client/fastembed,本机 uv/pip 缓存无其任何 wheel,hel857-venv(3.10.12 固定栈)存在且全部 SDK 回归在其上实跑;缺项=mem0ai 2.2.1/qdrant-client 1.20.0/fastembed 0.9.1 的 cp311 manylinux2014_x86_64 wheel,落位命令照 deploy/hel874-release.md §4 不变,本卡零下载",
|
||||
"acceptance": [
|
||||
"包含关系与机械性:合并前核实 bf234570 不是 152479b 祖先、git diff 31970c4 152479b -- web/ 为空;合并后 git diff bf234570 HEAD -- web/ 为空、git diff 152479b HEAD -- src tests tools config 为空(仅 9 个前端/治理文件变化),无重设计无视觉决定,原作者六文件与 CSS 可追溯",
|
||||
"合成后工程检查在本 head 全过:299 pytest(3.11.16 venv + requirements.lock 离线)、ruff 0 错(src/tests/tools)、web typecheck 0 错/lint 0 错 1 既有警告/vitest 55/55/build 通过且 CSS 哈希 index-DdDYzR5S.css 不变",
|
||||
"HEL-894/889/886/885/874/882 回归全绿(固定 SDK 确定性替身 + 仅回环):verify_close_ownership_hel894.py 16/16、verify_shutdown_queued_hel889.py 12/12、verify_inflight_lifecycle_hel886.py 6/6、verify_semantic_recovery_hel885.py 7/7、verify_mem0_real_hel874.py 12/12、check_release_offline_hel882.py R1–R7 15/15",
|
||||
"真实 HTTP 分页合同 7/7(tools/verify_http_pagination_hel895.py 对真实服务):无档案 404 负例;首页恰 50 行升序 next_before=本页最小 id;沿 next_before 整走 327 行无重无缺页边界正确;公开允许清单字段恰为 id/ts/role/text/turn_id/status/lifeIds(+proactive) 且 proactive 恰在播种留言行;fetchAfter 缺口游标(HEL-880)真实服务复验:5 页封顶缺口保留→下次补齐→两条新留言按 id 序恰好交出一次;epoch 分页稳定、未知路径 404",
|
||||
"真实服务浏览器 7/7(web/tests/hel895_real.mjs,Chromium CDP 对真实 API):真实启动无服务未接通卡;新留言行写入后 20 秒内/可见性触发读到达并出现留言卡;进交谈舞台播放;260 行长缺口在其下的新留言经补读到达且无重复;SIGTERM 重启(epoch+1)后同批行不加第二次;麦克风/相机权限保持 prompt 零申请",
|
||||
"发布候选文档 deploy/hel895-release-candidate.md 给出精确 head、交付物清单(requirements.lock 19 项固定依赖、前端产物 CSS 哈希一致、systemd/配置模板、独立数据空间、健康矩阵 R4-assembly/stub/诚实未接项、停用与保留数据回退)与 3.11 固定 SDK 准确缺项(零下载,落位路径不变)",
|
||||
"预算执行包 docs/budget-package-hel895.md:A/B/C 数值、四道闸叠加口径与交叉/重复/漏记核对结论(交叉=总量+日顶有意叠加;嵌入只记条数不进请求计数;四类别+嵌入+全池 token 覆盖全部出站点)、失败取消保守入账、碰顶停机与留证;随包默认全 0、权威账与冻结余额零写入(check_release_offline R3 复现未批即拒)",
|
||||
"双目标及实际母线需求检查各含/不含本 handoff 共 6/6 通过(origin/main、origin/agent/agent/de8874a3803b、实际母线 152479b)"
|
||||
],
|
||||
"deferred": [
|
||||
"真实预算授权:A/B/C 全部待白栖知经总管批准;批准前 cap 全 0=发送前拒绝;旧 39/60、498/500(冻结 2 条)与 HEL-835 闸不挪用不重置;真实调用、真实嵌入、权威账写入本卡零执行",
|
||||
"3.11 固定 SDK wheel 落位:本机缓存无 cp311 wheel,发布卡按 deploy/hel874-release.md §4 用 pip download(mem0-stack.lock)落 wheel 后离线并入并 co-import 验证;落位前 stub/FTS 不冒充真实 Mem0 体验就绪",
|
||||
"部署与体验地址:待总管复核通过 + 预算/部署授权后由发布卡按 deploy/hel895-release-candidate.md §2 执行(8360 隔离实例);本卡未部署、未合并 PR#11、未交体验地址;8300–8350 与共享语音口型未触碰",
|
||||
"R5 语音:HEL-878(原作者会话额度受限,已有定时唤醒)/HEL-879(待前端完成)继续接续;R6 天气/素材包/完整备份、R7 有条件视觉观察(默认关,需白栖知授权 + 4080 决策)均未接入,界面保持诚实文案,不冒充已运行",
|
||||
"真机与 Safari 未验证(等效视口与桌面 Chromium 已过);跨设备已读仍为本浏览器口径;即时到达需后端推送/正向分页属合同变更未做——沿用 HEL-881 承接口径",
|
||||
"整体沉浸体验方向:用户 2026-10-23 认可动效质感但整体沉浸感未满意、新方向未定;本卡为发布准备不接管视觉作者、不触其运行时/模型/认证;界面小样认可前不替换正式界面"
|
||||
],
|
||||
"requirement_changes": [],
|
||||
"verification": [
|
||||
"分支 hel-870-assembly 正常追加(精确 head 见交付评论,第一父 152479b、合入 bf234570),PR#11 只追加不强推不合并;视觉总监分支未覆盖",
|
||||
"python 3.11.16 venv + requirements.lock 离线:299 pytest 全过;ruff 0 错(src/tests/tools);web typecheck/lint(1 既有警告)/vitest 55/55/build 全过,CSS 仍 index-DdDYzR5S.css",
|
||||
"固定 SDK(hel857-venv 3.10.12 + mem0ai 2.2.1/qdrant-client 1.20.0/fastembed 0.9.1,确定性 512 维替身、仅回环、临时账库):verify_close_ownership_hel894.py 16/16(docs/rework/hel895/close-ownership-hel895.json)、verify_shutdown_queued_hel889.py 12/12、verify_inflight_lifecycle_hel886.py 6/6、verify_semantic_recovery_hel885.py 7/7、verify_mem0_real_hel874.py 12/12(同目录证据 JSON);check_release_offline_hel882.py R1–R7 15/15(release-offline-hel895.json,R6 如实记录 3.11 缺 mem0)",
|
||||
"新增 tools/verify_http_pagination_hel895.py:真实服务 7/7(docs/rework/hel895/http-pagination.json);新增 web/tests/hel895_real.mjs:真实服务 + Chromium CDP 7/7(docs/rework/hel895/real-browser.json 与 real-*.png 截图)",
|
||||
"python3 scripts/check_requirements.py --base-ref {origin/main | origin/agent/agent/de8874a3803b | 152479b} 各含/不含 --handoff docs/requirements/handoff-HEL-895.json 共 6/6 通过",
|
||||
"零真实 LLM、零真实嵌入、零非回环出站、零下载;权威三账与冻结余额未写;8300–8350、共享语音口型、GPU/4080 未触碰;未部署、未合并 PR、未交体验地址"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"baseline_version": "1.11",
|
||||
"read_commit": "04eff611e7d85e539d43717711172441420ac853",
|
||||
"task": "HEL-896 发布补齐:按总管独立复审(附件 HEL-895-总管独立复审.md 及证据 zip)一次修正四项发布工程与如实记载——①A/B/C 可执行分账与阶段切换(临时库复现共库误配、独立团队测试实例+全新用户实例方案、封账/授权来源/叠加口径/停续语义、一次有限推荐);②修真实浏览器验证误报(精确点击可见留言卡回她、严格断言舞台文本/未读变化/消息ID去重/重启epoch+1、权限API调用计数0、临时回环配置+拒绝非回环连接,保留原误报证据+勘误+修后证据,不改视觉产品);③SDK 离线可复用部分与准确余缺(41 项闭包逐项分类、mem0 固定源码身份哈希核验、fastembed 模型缓存实测、seq48–51 pip 26.2.2 下载事件缓存取证与勘误);④发布归档/回退改一致性快照(WAL 丢失复现、停服+checkpoint 与 backup API 双口径、可审核产物/哈希/命令/代码提交对应,不冒充 R6 完成)。零真实 LLM、零真实嵌入、除既有缓存外零新增下载、不部署、不合并 PR、不交体验地址、不触 8300–8350 与共享语音口型、不访问 4080、不写权威账、真实 cap 保持 0、不改任何队员运行时/模型/认证、不导入测试档案为用户伴侣",
|
||||
"requirement_ids": [
|
||||
"CG-006",
|
||||
"CG-008",
|
||||
"CG-009",
|
||||
"CG-011",
|
||||
"CG-012",
|
||||
"CG-013",
|
||||
"CG-014",
|
||||
"CG-015",
|
||||
"CG-018",
|
||||
"CG-021",
|
||||
"CG-023",
|
||||
"CG-029",
|
||||
"CG-030",
|
||||
"CG-031",
|
||||
"VIS-013",
|
||||
"AM-001",
|
||||
"AM-002",
|
||||
"AM-003",
|
||||
"UX-001",
|
||||
"UX-005",
|
||||
"UX-006",
|
||||
"GOV-001",
|
||||
"GOV-002",
|
||||
"GOV-003",
|
||||
"GOV-004",
|
||||
"GOV-005",
|
||||
"GOV-006",
|
||||
"DEL-001"
|
||||
],
|
||||
"deliverable": "分支 hel-870-assembly 正常追加 PR#11(不强推不合并):1) docs/budget-package-hel895.md 增 §6 可执行分账(独立团队测试实例 8360 独库独配置承载 A 的 55/500000 一次性总量、全新用户实例永不配置一次性总量、A 封账=停服+一致性快照归档+budget_total 永不清零、旧测试数据无导入用户库路径、B/C 开始的配置与授权来源、B 真实 Mem0 冒烟计入 60/180、B 到顶 queued 不丢行不耗重试、首周结束凭实际用量报告定停续、一次负责的有限推荐 A55/500k+B60/180+C 逐日顶),并勘误原文『A 当天同时受 C 类日顶约束』与『WAL 单文件整体归档』两处不安全表述;新增 tools/verify_budget_split_hel896.py 8/8(S0 共库误配复现与总管同形、S1 团队实例 55 硬顶+日顶取最紧、S2 封账跨重启跨归档、S3 用户实例 B/C 放行+日顶叠加+拒绝不落账、S4 误配守门、S5 仓库配置与权威事实零改动),证据 docs/rework/hel896/budget-split/budget-split.json;2) web/tests/hel895_real.mjs 修订(B2 信件卡精确断言+未读标记、B3a/B3b 导航日子→可见留言卡 aside.reach.show→只点该卡『回她』→严格断言 .conversation .sr 舞台原文+未读清零、B4/B5 服务器消息 ID data-mid 去重 0 重复、B5 epoch 恰 +1 实测 1→2、B6 页面自身 Permissions API/getUserMedia 调用计数 0、B7 临时回环 models.yaml+sitecustomize socket 守卫拒绝并计数非回环连接=0 且非回环 DNS=0);勘误前证据 browser-before/(原脚本逐字重跑 7/7 含 B3 stage=false 误报 PASS)、修后 browser/ 9/9;docs/rework/hel896/README.md 勘误说明;未改任何 web/src 产品代码,精确交互下舞台/未读/去重/epoch 语义真实成立,未发现产品行为缺陷;3) tools/audit_sdk_offline_hel896.py 只读审计:闭包 55 项/缺 41(纯 28+原生 13)逐项分类(立即可复用仅 greenlet cp311/pillow cp311/truststore py3-none-any 三项)、mem0ai 固定源码 direct_url+tarball SHA256 与 mem0-stack.lock 一致、索引同名 wheel 不作数、hel857 构建轮在临时缓存未持久、hatchling 离线构建待发布卡、fastembed 真实模型缓存 92MB 实测(bge-small-zh-v1.5+bm25)、pip 26.2.2 事件缓存取证(uv 条目创建于 2026-10-27 02:10:04、files.pythonhosted.org、窗口内唯一新增→该步发生了网络获取,前卡零下载不成立,按保守口径记为下载;requirements.lock 装机全部命中既有缓存);deploy/hel895-release-candidate.md §4 勘误为准确清单、后续安装强制 offline/no-index;4) tools/release_snapshot_hel896.py 一致性快照/回退工具(停服+checkpoint 与 backup API 双口径、逐文件 SHA256 MANIFEST、代码精确提交、逐表行数核对、verify 回退演练)自测 4/4:在线裸复制主 .db 复现 no such table: companion、backup API 与 checkpoint 两口径均完整、归档哈希与行数全过;§5 改一致性快照口径含照抄命令与覆盖范围(产品库/向量/推导史/权威账),不冒充 R6 完成;deploy/hel895-release-candidate.md 增 HEL-896 修订头与交付物表更新",
|
||||
"acceptance": [
|
||||
"分账方案可执行且经临时库+替身验证:tools/verify_budget_split_hel896.py 8/8 全过(共库误配复现与总管独立复现同形;团队实例 55 硬顶跨重启跨 backup API 归档不失效;用户实例无总量闸时 B/C 放行、日顶逐项到顶拒绝且拒绝不落账;误配总量守门;仓库配置与权威账零改动)",
|
||||
"docs/budget-package-hel895.md §6 明确 A 封账步骤、B/C 开始配置与授权来源、旧测试数据不会转成用户伴侣(无导入路径+发布检查单禁复制)、全局累计与日顶叠加口径、B 到顶与首周结束的停/续授权语义、A stub 检查/真实 Mem0 冒烟/B 首周/C 日常关系、一次负责的有限推荐;原文两处不安全表述已勘误标注",
|
||||
"浏览器验证误报修正:原脚本逐字重跑复现误报(B3 stage=false 仍 PASS,7/7 作废口径);修订版 9/9 全过——精确点击可见留言卡的回她、舞台 .conversation .sr 含留言原文、未读标记真实清零、记录 data-mid 全无重复且缺口/现场留言各恰一次、/api/health epoch 恰 +1(1→2)、页面自身权限 API 调用计数 0、非回环连接尝试 0 且非回环 DNS 0(回环配置+socket 守卫强制拒绝);产品代码零改动,原证据保留+勘误+修后证据三件齐",
|
||||
"SDK 余缺准确清单:闭包 55/缺 41 与总管独立计算一致;三个顶层包 WHEEL 均 py3-none-any;mem0ai 固定源码身份(direct_url+tarball SHA256 与 lock 注释一致)核实;缓存可复用仅 3 项、其余 37 项+离线构建依赖准确留给发布卡不阻塞;fastembed 模型缓存实测 92MB 两模型;pip 26.2.2 事件取证明确(该步发生网络获取,前卡零下载勘误不成立,保守记为下载;lock 装机无新增缓存条目);本卡零下载零安装零推理",
|
||||
"发布归档/回退一致性:在线裸复制丢 WAL 已提交行复现(no such table: companion);停服+checkpoint 与 backup API 双口径快照完整;归档含逐文件 SHA256+代码精确提交+逐表行数核对;verify 回退演练全过;§5 命令与覆盖范围(产品库/语义向量/推导史/权威账)可照抄,不删档,不冒充 R6 完整备份完成",
|
||||
"全量回归在本 head 实跑:3.11.16 venv + requirements.lock 离线 pytest 299/299、ruff 干净(src/tests/tools);web typecheck 0 错、lint 0 错 1 条既有警告、vitest 55/55、build 通过 CSS 仍 index-DdDYzR5S.css;固定 SDK 回归(hel857-venv 3.10.12 替身+回环)verify_close_ownership_hel894 16/16、verify_shutdown_queued_hel889 12/12、verify_inflight_lifecycle_hel886 6/6、verify_semantic_recovery_hel885 7/7、verify_mem0_real_hel874 12/12、check_release_offline_hel882 R1–R7 15/15;真实 HTTP 分页合同 7/7;三目标需求检查各含/不含 handoff-HEL-896 共 6/6"
|
||||
],
|
||||
"deferred": [
|
||||
"R5 语音仍由 HEL-878/879 接续;R6 天气/素材/完整备份(CG-009 每日自动备份与手动导出)未接入,本卡一致性快照只是发布归档/回退要求,不冒充完成",
|
||||
"R7 有条件视觉观察继续保留;手机真机与 Safari 未验证",
|
||||
"真实部署、体验地址、PR 合并、真实预算写入、SDK 41 项缺口的授权下载与离线并入、真实 Mem0 激活(B)与团队整体检查(A)执行:全部留给发布卡经总管向白栖知一次申请批准后执行;A/B/C 批准前所有 cap 保持 0 fail-closed",
|
||||
"视觉方向讨论与整套界面验收仍由视觉总监线承接;本卡未改任何界面文件"
|
||||
],
|
||||
"requirement_changes": [],
|
||||
"verification": [
|
||||
"docs/rework/hel896/budget-split/budget-split.json(8/8)、docs/rework/hel896/browser-before/(误报复现)与 docs/rework/hel896/browser/(修后 9/9 + netguard 报告 + 截图 + run-commands.txt)、docs/rework/hel896/sdk-audit/sdk-audit.json+summary.md(含 pip 事件缓存取证)、docs/rework/hel896/release-snapshot/selftest.json(4/4)",
|
||||
"HEL-895 原始证据 docs/rework/hel895/ 原样保留未改;总管复审附件与其独立证据 zip 引用见 docs/rework/hel896/README.md",
|
||||
"回归命令与需求检查输出见交付评论;人工核对原话:GOV-006(01a1734c)、完整体验委托(01a1780e 原话『我觉得这是工程问题…直奔核心』)已由本卡阅读并在方案中落实为『不再问用户选择算法、直接接续已授权工程』",
|
||||
"未验证:真机/Safari/手机、真实 LLM 与真实嵌入行为(本卡零真实调用)、目标发布机的实际归档执行(工具已自测,发布卡照抄)"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
{
|
||||
"baseline_version": "1.11",
|
||||
"read_commit": "b95ce798b4a9455d941d247a46865b3ac202bf2c",
|
||||
"task": "HEL-897(HEL-878 有限返修,视觉总监本人编码):修正重开语音被旧掉线结果覆盖——旧会话 fail() 在 await teardown 之后提交 OFF,覆盖已 listening 的新会话;并检查同一失败/结束/重开路径中 await 前后的代次与所有权。不重新设计,不改视觉",
|
||||
"requirement_ids": [
|
||||
"CG-010", "CG-018",
|
||||
"VIS-013",
|
||||
"UX-005", "UX-006",
|
||||
"GOV-001", "GOV-002", "GOV-003", "GOV-004", "GOV-005", "GOV-006",
|
||||
"DEL-001"
|
||||
],
|
||||
"deliverable": "自 HEL-878 原稿(总管保全提交 b95ce798,13 文件哈希逐一核对一致)起的补丁,只动 web/src/voice/session.ts 与测试:1) start() 内 fail():代次与 live 释放后先发起 teardown(麦克风同步先停、房间关闭与 DELETE 已发出),立即在本会话仍拥有页面时提交 OFF 与失败提示,再等待清理完成;清理迟到返回只释放旧会话自己的麦克风/房间/服务端房间,之后不再写界面。2) start() 先同步取得新代次与 live,再等待被替换会话的清理(原先 await end() 之后才取代次:两次开启交错时,较早一次醒来会抢走代次、把已接通的新会话孤立在外,其麦克风与房间不再被释放);被替换后醒来即退出;settle 补发在取得代次之后。3) web/tests/voice.test.ts 新增「a late end of an older call」6 项(掉线/麦克风被撤销各一,worker 未加入超时,正常结束慢 DELETE,交错重开,迟到麦克风授权);Server 假件增加按会话挂起 DELETE。4) web/tests/review878_late_cleanup.test.ts:总管独立负例原样纳入。5) hel878_mock.mjs 增加 /__hold-delete 控制;hel878_shots.mjs 增加第 12 段后 HEL-897 浏览器复现 4 项。",
|
||||
"acceptance": [
|
||||
"总管负例 review878_late_cleanup.test.ts:修前失败(Expected listening / Received off,与总管日志一致),修后通过;测试未改",
|
||||
"掉线与麦克风被撤销后,旧 DELETE 与 settle 补发都挂起期间重开:新会话 listening、active=true、无旧提示;放行后界面不再变化;旧麦克风已停、旧房间已关,新麦克风/房间未被停;服务端只剩新房间;再结束后全部清空(单测各 1 项)",
|
||||
"worker 未加入超时失败且 DELETE 慢、正常结束 DELETE 慢后重开、两次开启交错(前一次仍在等旧房间归还)、迟到麦克风授权:只有最新会话存活,界面与 active 一致(单测 4 项;交错一项修前失败,暴露同路径的第二处代次漏洞)",
|
||||
"修前对照:同一测试集在原 session.ts 上 5 项失败(总管负例 + 新增 4 项),修后 33/33",
|
||||
"浏览器(无头 Edge,脚本化 LiveKit 替身与假音频设备):掉线后旧 DELETE 挂起,提示与停麦立即生效;新会话 listening;放行旧 DELETE 后新会话仍 listening、无旧提示、1 路活麦克风、她的音频在、服务端只剩新房间;结束后全部清理。修前构建 45/49(实测 phase=off 而新麦克风仍活),修后 49/49,原 45 项(结束/导航/Esc/结束交谈/断网/卸载/快速开关等退出路径)全部保持通过",
|
||||
"工程:tsc 0 错;eslint 0 错(1 条既有警告);vitest 8 文件 88/88;vite build 通过"
|
||||
],
|
||||
"deferred": [
|
||||
"CG-011 语音内主动开口、她说话时的增量字幕、断网时远端即时清理/租约与 API 重启实情、真实 SDK 回调与播放回执、真机连续三轮/打断/停麦/HTTPS/Safari 全部未测,仍交 HEL-879 统一审核;本卡单测与浏览器均为替身与假设备,不是 WebRTC 通话",
|
||||
"原版 Python 需求检查未在本运行时执行(无 Python、无 git),须总管对实际目标分支复跑(含/不含 handoff-HEL-878.json 与本交接);未用 Node 移植版冒充通过",
|
||||
"总管在前端分支从 04eff611 补齐的历史原话文件与 source-manifest 以总管保全分支为准;本补丁不触碰需求目录中除本交接以外的任何文件",
|
||||
"D1 音色、D3 设备信任由总管与白栖知沟通;R6/R7、CG-028/029 仍由主卡 HEL-797 承接;整体沉浸体验由白栖知验收"
|
||||
],
|
||||
"requirement_changes": [],
|
||||
"verification": [
|
||||
"读取:总管 HEL-897 卡与附件(HEL-878-总管复核.md、preservation-878.json、review878-race.log、review878_late_cleanup.test.ts);本人 HEL-878 原稿树(逐文件 SHA-256 与 preservation-878.json 13 项一致后才施工,原稿另行备份);需求与 integration-plan R5/D1/D3 沿用 HEL-878 已读内容,本卡无需求变更",
|
||||
"web:tsc --noEmit 0;eslint src 0 错 1 既有警告;vitest run 8 文件 88/88(原 81 + 本卡 6 + 总管负例 1);vite build 通过;node_modules 沿用 HEL-878 离线树,未下载、未安装",
|
||||
"修前/修后:同一测试集与浏览器脚本分别在原 session.ts 与修正版上运行,日志随交付包",
|
||||
"无模型、嵌入、合成、识别请求,无真实麦克风采集,无部署、合并、服务或绑定改动;未改后台与 HEL-896 发布包"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
{
|
||||
"baseline_version": "1.11",
|
||||
"read_commit": "f92a86f5d8f839338311cdee08179049de34eb20",
|
||||
"task": "HEL-898(HEL-879 接线卡,视觉总监本人编码):在已认可的交谈界面接上她的增量字幕(cg.subtitle 契约 v2)与语音内主动开口呈现,处理打断/文字接管/错误/挂断收尾;不另做聊天页、不改主题与整体动效;f92a86f 统一复核后的有限返修三项(worker 离场诚实收场、已退休 speech 不复活、短语音回复播放中可见)及回放基础设施",
|
||||
"requirement_ids": [
|
||||
"CG-004", "CG-006", "CG-010", "CG-011", "CG-018", "CG-020",
|
||||
"VIS-001", "VIS-002", "VIS-003", "VIS-004", "VIS-005", "VIS-006", "VIS-007", "VIS-008", "VIS-009", "VIS-010", "VIS-011", "VIS-012", "VIS-013",
|
||||
"UX-001", "UX-002", "UX-005", "UX-006",
|
||||
"AM-001",
|
||||
"GOV-001", "GOV-002", "GOV-003", "GOV-004", "GOV-005", "GOV-006",
|
||||
"DEL-001"
|
||||
],
|
||||
"deliverable": "自总管输入包 3228b1e(INPUT-MANIFEST 逐文件 SHA-256)起的前端补丁,只动 web/src/voice/session.ts、web/src/chat/ChatPanel.tsx 与测试:1) session.ts 严格解析 v2 信封(v===2、正整数 seq、kind 白名单、角色与种类对应、她的事件必带 speech_id、assistant_final 必带 turn_id、proactive_* 必带正整数 message_id;不合格整条丢弃且不推进序号);每次通话(控制器代次)独立 seq 高水位,seq<=已应用即丢;按 speech 生命周期只接受当前打开的一轮,已关闭/被取代的 speech 不再显示,旧 speech 的高 seq 事件不能关闭新轮。VoiceView 新增 her(speech/text/state open|final|done/turnId/messageId/proactive),与用户 ASR 草稿 heard 分槽。2) turn_start 开轮,assistant_interim 整句替换,assistant_final 原子替换为落库文本并请页面回读 /api/messages,turn_end 关轮(无 final 的关轮按未成为正式回复即清),turn_cancel/error(φ)/user_final/文字接管 hush/结束/掉线/卸载/重开即时清;φ 原句仍在语音行以“未记入聊天”显示。3) proactive_start 以落库原文、同源 message_id 显示在她的位置,proactive_end 保留至记录或下一轮接替,proactive_cancel 即清;不发任何请求、不标已读、不开麦、不重 TTS、不进入正式记录。4) ChatPanel:她的语音行进入与文字回复相同的舞台槽位(当前一两句、自动续读、暂停/回看、全文),生长中沿用文字流的“最新一句先压住”规则,逐分片不重启动画;落库行到来时同一 turn 同一位置接替,行键不变不重放;被撤回的语音行以 instant 方式立即离场(不淡出);减少动态设置沿用既有逻辑。你用语音开始新一轮时与发送文字一致恢复自动呈现(原先暂停状态下她的回答不会进来)。5) 测试:voice.test.ts 改为 v2 帧并新增 11 项(录制样例三场景回放、信封负例、乱序/重放/迟到/双 handle、φ、主动开口及打断、文字接管/挂断/重开、舞台行键接替);fake-livekit.js 未带信封的帧自动套 v2;hel878_mock.mjs 增 /__proactive;hel878_shots.mjs 的她的 final 与 φ 改为 v2 生命周期;新增 hel898_shots.mjs(两主题×电脑/手机)。【f92a86f 有限返修,首轮读取 3228b1e;本轮输入包 166 文件 SHA-256 全符】1) livekit.ts 监听 RoomEvent.ParticipantDisconnected(vendor 2.22.4 原名 participantDisconnected,emit(participant, reason)),只在本房间她的 worker(按身份记住的 agent 或 isAgent)离开、且房内没有其他 agent 时报 agentLeft;房间关闭中不报。session.ts 的 RoomEvents 新增 agentLeft:仅当前代次且 agent 已接入时走既有 fail(清字幕/草稿、停麦、清播放、关房、DELETE 本次服务房,失败入欠账重试),中文提示 WORDS.agentLeft;普通参与者离场、旧房间迟到离场、用户主动挂断都不触发。2) 已关闭 speech 由 64 项窗口数组改为每次通话一个 Set,随通话代次释放;seq 严格门不变。3) 语音回复开放态改为 live=speaking:reading.pagesOf 对其最后一块只显示已成句部分(。!?!?… 及其后的收尾引号括号),未成句部分仍压住;文字流 live=generating 的规则不变。已显示的语音行之后只会在同键下增长(短句与下一句合并时):LineStage.grow 原位追加新字的既有墨迹,不重建行、不重放;减少动态时直接设文本。ChatPanel 签名对语音行计入文本,全文页“还在说…”也适用于 speaking;ReadingClock 对同键增长只延长停留时间。没有新布局或样式。4) 测试:hel879_frames 的 DOCUMENTED GAP 改为拒绝断言,并新增每通话独立用例;voice.test 新增短回复/长句/文字流不变用例;新增 hel898_agent_left.test.ts(真实 livekitTransport 适配器 + 脚本化 SDK 事件名,另有控制器负例);fake-livekit.js 增 ParticipantDisconnected/leave/lateLeave/guest;hel878_mock.mjs 增 /__pid、/__reset,监听失败即退出;hel879_unified_shots.mjs 修回放基础设施(端口空闲与 pid 确认、多段录制按当前通话单调重编号并写 seq-renumbering.json、新通话重置、每主题 /__reset 隔离、负例原样发送并断言拒绝),加三项正反例和 CDP screencast→WebM 录屏",
|
||||
"acceptance": [
|
||||
"假 LiveKit 有序回放 normal-turn.jsonl:用户草稿→用户终稿→turn_start→两次增量(整句替换)→final(带 turn_id)→turn_end;她的字在舞台出现时 /__rows 尚无该回复;落库后记录中只出现一次(页面只回读,不写)",
|
||||
"interrupt.jsonl 与负例:turn_cancel 后她的未完成行立即离场;被取消轮之后的高 seq 增量/final/重复 turn_start 均不显示;整段录制重放不改变界面;双 handle 时旧 speech 的 turn_end/turn_cancel 不关闭新轮;无 final 的 turn_end 视为未成为正式回复并清除",
|
||||
"φ:error 原句在语音行显示并标“未记入聊天”,她的增量行立即清除,随后 turn_cancel(error_phi) 不抹掉 φ 原句;不落正式记录",
|
||||
"proactive.jsonl:原文一字不差显示在她的位置并保留落库行身份(id/turn),可被你的语音打断(proactive_cancel 即清);全程页面无任何非 GET 请求(无回执、无已读、无消息写入),不调用 onSpoke/onRecord",
|
||||
"文字接管、结束语音、掉线、新通话:她的行即时清;旧房间迟到帧被代次挡住;新通话序号从 1 重新开始并正常显示",
|
||||
"两主题(月光/雾光)电脑 1440×900 与手机 390×844 截图与连续帧:沿用已认可位置与组件,无新增组件或样式;减少动态设置下她的字照常出现、无入场动画",
|
||||
"工程:tsc 0 错;eslint 0 错 1 条既有警告(ChatPanel fullButton ref,HEL-897 起即有);vitest 8 文件 99/99;vite build 通过;浏览器 hel898 61/61,HEL-878 回归 49/49;修前对照:新 voice.test.ts 在原 session.ts/ChatPanel 上 12 项失败",
|
||||
"f92a86f 返修-1:worker 离场(房间仍开)时通话即时结束:她的行清除,提示“她那边的语音中断了……”,麦克风轨 ended,播放容器移除,本次 session DELETE 恰好一次;普通参与者离场不挂断;旧房间迟到离场不影响新通话;用户主动挂断只有一次 DELETE、没有离场提示;DELETE 失败入欠账并重试(单测)",
|
||||
"f92a86f 返修-2:adversarial-gates 66 次挤出后,speech_A 以新 seq 重开/增量/终稿都被拒(单测与浏览器原样探针),之后新 speech 正常进入;新通话从 seq 1 开始,不受旧通话已退休 id 影响",
|
||||
"f92a86f 返修-3:worker-normal 回放中“在听呢,”“…那件事”未成句时舞台不显示她的半句;第三个增量成句后、final 之前即显示整句,并在播放期间保持;final 与落库行接替为同一 DOM 行(不重建、不重放);短句与下一句合并时同节点原位增长、首字墨迹不动;长句只显示已完成的行、不整段铺满;文字流仍压住最新块",
|
||||
"f92a86f 返修工程:tsc 0;eslint 0 错 1 条既有警告;vitest 10 文件 118/118;build 通过;修前对照 vitest 7 项失败;统一实际 worker 帧浏览器回放(moon/fog × 电脑/手机 + 减少动态)修后 53/53、修前 30/53(失败都落在三项及其连带);hel898_shots 61/61、hel878_shots 49/49;8 段 WebM 录屏取自真实 screencast 帧"
|
||||
],
|
||||
"deferred": [
|
||||
"真实通话未测:真实 LiveKit/WebRTC、真实 worker 与 SDK 回调时序、真机/Safari/iOS、可信 HTTPS+WSS、R5 连续三轮/1 秒打断/停麦无残音/有限预算,均仍由 HEL-797 主卡承接;本卡全部为假 LiveKit、假音频设备与 Chromium 无头 Edge",
|
||||
"CG-011 语音内主动开口仅是“会话开时念一条已落库旧留言”的最小接缝(后台默认关,本卡不启用);会话中持续主动联系、激活节奏、未读联动策略未完成,不得记为 CG-011 完成",
|
||||
"后台并行小修(建房延迟后的清理唤醒、主动 say 的 start 发得过晚、无完整 receipt 错误发 final)由原总工在 HEL-879 处理;本卡按 v2 正确语义实现,最终后台 commit 出来后需按其统一复核(特别是 proactive_start 晚于音频开始时的呈现)",
|
||||
"已知边界:seq 按“一次 worker job 一个序列”实现;若同一房间内 worker 重连且序号归零,前端会按契约丢弃其帧直到超过旧高水位——需后台确认 job 与房间一一对应",
|
||||
"原版 Python 需求检查(scripts/check_requirements.py --base-ref origin/main,含本交接)未在本运行时执行(无 Python、无 git),须总管对实际目标分支复跑",
|
||||
"D1 音色、cap=0、R6/R7、整体沉浸体验由主卡与白栖知决定;工程自测不是用户体验验收",
|
||||
"f92a86f 返修:真实 SDK 下 worker 离场事件的时序(含网络重连期间 remoteParticipants 被清空但不发离场事件)只按 vendor 源码核对,未在真实房间验证",
|
||||
"回放基础设施把多段录制重编号(原始帧保留在 fixtures,映射见 seq-renumbering.json),证明的是页面在“同一通话单调 seq”下的呈现与门,不证明 worker 跨 job 的 seq 行为"
|
||||
],
|
||||
"requirement_changes": [],
|
||||
"verification": [
|
||||
"读取:HEL-898 卡(启动交接与原说明)、输入包 3228b1e:docs/voice-subtitle-contract-v2.md、docs/rework/hel879/voice-seam-interfaces.md、subtitle-samples/*.jsonl、src/cybergril/voice/seam.py 与 worker.py(事件发出点)、AGENTS.md、docs/requirements/README.md/current.md(v1.11)/coverage.md/changes.md、sources/integration-plan-v1.md R5",
|
||||
"工具:沿用本机既有离线工具链(HEL-834 留存 node v22.11.0;HEL-897 留存 web/node_modules,package-lock 哈希与本包一致,目录联接使用);未下载、未安装",
|
||||
"web:tsc --noEmit 0;eslint src 0 错 1 既有警告;vitest run 8 文件 99/99(原 88 + 新增);vite build 通过;日志随交付包",
|
||||
"浏览器:node tests/hel878_mock.mjs + node tests/hel898_shots.mjs(无头 Edge、脚本化 LiveKit 替身、Chromium 假音频设备)61/61;node tests/hel878_shots.mjs 回归 49/49;截图与连续帧随交付包",
|
||||
"无模型、嵌入、ASR、TTS 请求,无真实麦克风采集,无部署、合并、服务或绑定改动;未改后台、总装分支或 PR#11",
|
||||
"f92a86f 返修读取:卡内三项说明、HEL-898-统一复核返修输入-f92a86f.zip(166 文件 SHA-256 全符)、web/public/vendor/livekit-client-2.22.4.umd.min.js 中 RoomEvent.ParticipantDisconnected 的定义与 emit(participant, reason)、断开清理路径不发该事件;本包缺 docs/rework/hel879/subtitle-samples,测试运行时沿用 3228b1e 输入包同名文件(不入补丁)",
|
||||
"f92a86f 返修浏览器:node tests/hel879_unified_shots.mjs <msedge> <out> 8879 9499(自带 mock,先确认端口空闲与 pid);hel898_shots/hel878_shots 由本运行自起 mock(核对 pid 后按 PID 停止)"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
{
|
||||
"baseline_version": "1.12",
|
||||
"read_commit": "8dc84f88e9d5e961e17b246f24c23eaf526b012e",
|
||||
"task": "HEL-899:把现有 CosyVoice 参考音频零样本克隆能力接入 CyberGril 统一 API(网页上传/录制参考音频→登记 cg- 专属 ID→试听现合成→应用到同一位她的后续通话);直接复用 .12 语音面板 8090 的 zero-shot 注册与 CosyVoice 热加载、9880 /tts 合成,不训练新模型、不重造克隆引擎、不自建第二写者;本卡只做后台/协议与零真实调用自测,前端按合同接视觉总监,真实试听放统一审核",
|
||||
"requirement_ids": [
|
||||
"CG-006",
|
||||
"CG-009",
|
||||
"CG-010",
|
||||
"CG-013",
|
||||
"CG-014",
|
||||
"CG-015",
|
||||
"CG-016",
|
||||
"CG-018",
|
||||
"CG-019",
|
||||
"CG-020",
|
||||
"CG-021",
|
||||
"AM-001",
|
||||
"GOV-001",
|
||||
"GOV-002",
|
||||
"GOV-003",
|
||||
"GOV-004",
|
||||
"GOV-005",
|
||||
"GOV-006",
|
||||
"DEL-001"
|
||||
],
|
||||
"deliverable": "src/cybergril/voice/custom.py(CustomVoiceService:8090 面板代理=共享 voices.json 唯一写者、cg-+8hex 服务端生成 ID 不撞既有 11 支、WAV 头服务端复验 RIFF/WAVE≤15MB≥2s、显式 allow_asr 才走 FunASR 转写、试听先验存在拦住 CosyVoice 未知音色静默回落 default、原子落盘+失败整体回滚、选择/元数据/资源流水持久在实例资料空间重启读回、备份清单 manifest);router.py 五个新端点(GET/POST /api/voice/voices、POST /api/voice/preview、GET/POST /api/voice/selection)+ /api/voice/session 响应新增 voice=本次通话捕获音色(选择失效诚实回落 default;未选择不代写 worker 文件不替 D1 定音色);session.py 会话记录 voice 字段+/health 名单读回;worker 语义不变(入口读一次→通话中改选最迟下一通话生效、绝不半句换人);契约文档 docs/voice-custom-contract-HEL899.md(前端可直接实现的请求/响应/错误/录音格式/部署与回滚);config/voice.example.yaml 增补(panel_url/tts_url/registry_file/worker_state_file,env 可覆盖);零新依赖(登记端点原始字节体+查询串,特意不引 multipart 库);tests/test_voice_custom.py 18 项 + scripts/verify_hel899_custom_voice.py 12/12;治理:v1.12(CG-010 边界更新,来源评论 01a17de1-2892-78be-a422-eb6a11ffebfd 逐字录入 sources/comment-evidence-custom-voice-20261027.json + manifest/baseline/coverage/changes 同步)",
|
||||
"acceptance": [
|
||||
"完整最小合同成立:列出可用声音(builtin 11 支+custom 标记、选择/试听状态、备份清单字段)、登记参考音频(服务端生成 cg- 专属 ID,不可能撞名覆盖既有 11 支,撞名重试不覆盖)、试听生成(每次现合成 WAV 24k/mono、无缓存不拿旧音频冒充)、读取/应用专属音色(换声音只换发声)全部经统一 API,浏览器不直连 8090/9880,凭据不下发",
|
||||
"当前 session/chat 业务不分叉:worker/统一聊天链零改动;通话开启捕获有效音色并写入会话记录与 worker 状态文件,通话中改选不影响本通话、最迟下一通话生效(测试断言会话 voice 定住)、不打断或误认原轮次/receipt(receipt 链路未动)",
|
||||
"原子与失败诚实:登记失败(面板 400/5xx/断连/谎报成功)不留下半条可选项、无元数据残留;应用失败整体回滚(选择状态与 worker 文件都回旧值);服务不可用一律 503 中文文案;ASR 仅在 allow_asr=true 显式准许且参考文字为空时发生(面板 FunASR,非 LLM),每次记 register_asr/preview_tts 流水可核算",
|
||||
"试听不写聊天/记忆/生活/回执(四表计数零变化测试断言);自定义音色未试听不得应用(409),内置 D1 候选不强制;未知音色 404 且 TTS 零调用(前置拦住 CosyVoice 静默回落 default);未知选择通话开启诚实回落 default 不冒充",
|
||||
"持久化与身份不变:选择/元数据/试听凭据重启读回(重建服务同批文件测试);换声音不改 companion/bazi_core/chat_message(逐字节对比测试);通用助手 voice_state/persona_state/既有音色零写入零删除(桩端点计数零);无人经 API 选择时不代写 worker 文件(D1 域不替用户定)",
|
||||
"零真实调用:全链 fake 面板/TTS/LiveKit 传输,零真实 LLM/嵌入/ASR/TTS、零模型下载/安装、零共享音色实写、零部署、零现网触碰、未访问 4080、未动 HEL-879 现场"
|
||||
],
|
||||
"deferred": [
|
||||
"真实 CosyVoice 试听/真实 FunASR 转写/克隆相似度:统一审核卡在获批环境实测,复用合法剩余额度,不另开账绕 HEL-879 上限(最长2小时/3次通话授权属总管测试执行,不在本卡)",
|
||||
"前端入口(上传/录音/试听/应用 UI 与入口呈现):视觉总监按 docs/voice-custom-contract-HEL899.md §2 契约接线;本卡未动 web/",
|
||||
"自定义音色删除与完整备份/恢复(CG-009/R6):本卡最小合同不含删除(失败/多余登记不影响使用),备份清单字段已就位,恢复=按清单重新登记(面板无导出接口)",
|
||||
"D1 最终音色决定仍归白栖知/总管;本轮测试音色已授权总管自定",
|
||||
"R5 整体真机验收与 R1–R7 完整要求继续承接;自定义音色交付不等于 R5 完成或整产品完成"
|
||||
],
|
||||
"requirement_changes": [
|
||||
{
|
||||
"summary": "v1.12:CG-010 音色边界更新为可自定义音色(网页上传/录制参考音频→试听→应用,直接复用已装TTS零样本克隆,不以仅选预设替代,参考包试听方案不采用);影响仅 CG-010 音色入口与测试授权,换声音只换发声等既有边界不变",
|
||||
"approval_comment_id": "01a17de1-2892-78be-a422-eb6a11ffebfd",
|
||||
"record": "sources/comment-evidence-custom-voice-20261027.json + changes.json/changes.md v1.12 + baseline.json/coverage.json/current.md 同步"
|
||||
}
|
||||
],
|
||||
"verification": [
|
||||
"PYTHONPATH=src .venv311/bin/python -m pytest tests -q:370 通过(基线 8dc84f8 全量 352 + 本卡 18:tests/test_voice_custom.py,全 fake 面板/TTS/LiveKit httpx.MockTransport + 临时文件 + 隔离 registry,零网络零真实模型调用)",
|
||||
"scripts/verify_hel899_custom_voice.py:12/12 全过(真实 app+router+service,fake 传输:列表→无准许拒ASR→显式登记→未试听409→试听现合成→应用→会话捕获→通话中改选定住本通话→下一通话生效→capabilities.voice=false→重启读回选择/元数据/试听凭据)",
|
||||
"ruff check src tests scripts deploy:本卡代码 0 错(既有 deploy/hel835_guard.py 的 SIM115 遗留不变,非本卡)",
|
||||
"python3 scripts/check_requirements.py --base-ref origin/main 与 --base-ref 8dc84f8(实际基准):含本 handoff 通过(v1.12 升版+新来源+变更记录合法,历史来源与变更未改写)",
|
||||
".12 只读取证(SSH 零写入零服务触碰):/opt/voice-agent/web/server.py 实读核对 upload 校验(名字规则/15MB/WAV magic/32000字节/空参考文本→FunASR 转写/失败删 wav/voices.json 原子写)、/opt/voice-agent/cosyvoice/server.py 实读核对 mtime 热加载与 /tts 未知音色静默回落 default、voices.json 11 支音色清单——契约按实际源码写,不按记忆",
|
||||
"未验证如实声明:真实 CosyVoice 合成与 FunASR 转写未调用(TTS 9880 停机中且本卡零真实调用);浏览器端录音上传未实现(前端合同已交);.12 未部署、未改任何现网配置/端口/数据"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"baseline_version": "1.12",
|
||||
"read_commit": "ce7279e68f64319c080f7ef150cb86c892b81ecb",
|
||||
"task": "HEL-900:在已认可的设置界面接入自定义声音——网页上传或录制参考声音→登记→试听实际合成→应用给同一位她的后续通话;按 docs/voice-custom-contract-HEL899.md §2 接 HEL-899 后台(agent/2/652da8a82e50 @ ce7279e),只改 web/,零真实调用",
|
||||
"requirement_ids": [
|
||||
"CG-006",
|
||||
"CG-009",
|
||||
"CG-010",
|
||||
"CG-013",
|
||||
"CG-014",
|
||||
"CG-015",
|
||||
"CG-016",
|
||||
"CG-018",
|
||||
"CG-019",
|
||||
"CG-020",
|
||||
"CG-021",
|
||||
"VIS-003",
|
||||
"VIS-004",
|
||||
"VIS-008",
|
||||
"VIS-010",
|
||||
"UX-003",
|
||||
"UX-006",
|
||||
"AM-001",
|
||||
"GOV-001",
|
||||
"GOV-002",
|
||||
"GOV-003",
|
||||
"GOV-004",
|
||||
"GOV-005",
|
||||
"GOV-006",
|
||||
"DEL-001"
|
||||
],
|
||||
"deliverable": "设置面板新增「她的声音」分区(沿既有设置结构、组件与两套主题 token,不另起视觉方向):web/src/voice/custom.ts(同源 API 客户端:GET/POST /api/voice/voices、POST /api/voice/preview、POST /api/voice/selection;浏览器解码任意可解音频→16kHz 单声道 16 位 PCM WAV 原始字节体上传,参数走查询串;≥2 秒/≤15MB/静音/解不开在浏览器先拦;allow_asr 仅在参考文字为空且用户明确打开开关时为 true;试听响应须为合法 WAV 才可播放;Recorder 仅由点击开启、只录音频、停止/取消/离开/音轨中断即释放、20 秒自动停、迟到的麦克风授权立即关闭);web/src/manage/VoiceSection.tsx(现在的声音与生效时机、上传/录音二选一、参考原声与「她用这个声音说的·刚刚现场合成」分开标注的主题化播放条、名字/参考文字/转写开关、登记、可用声音列表、试听→浏览器 canplay 确认可播后才能应用、每类请求一代 AbortController + 进行中引用防重复、切换/重试/离开/卸载释放请求与 objectURL、失败保留输入);ManagePanel 接入分区、未登记的参考声音计入未保存离开确认、能力标签随服务器实际状态;components.css 追加分区样式(只用既有 token,两主题与手机断点);离线 mock tests/hel900_mock.mjs、浏览器驱动 tests/hel900_shots.mjs、单元测试 tests/hel900_custom_voice.test.ts",
|
||||
"acceptance": [
|
||||
"用户可在网页选择本地音频文件或主动点「开始录音」得到参考声音;产物为真实 PCM WAV(mock 端按 RIFF/WAVE 头核验 16kHz/单声道/16 位、时长≥3 秒、Content-Type audio/wav、原始字节体),改扩展名的非 WAV 在浏览器被拒且零上传",
|
||||
"参考文字可填写;留空时须用户明确打开转写开关才传 allow_asr=true,默认不代开;已填写参考文字时一律 allow_asr=false;转写结果回显",
|
||||
"参考原声与实际合成试听分开标注(「你给的声音,不是她的声音」/「刚刚现场合成·不是参考原声」);试听每次重新请求,非 WAV 响应拒绝播放;浏览器 canplay 确认本次新试听可播后「给她用这个声音」才可点;切换声音、重试、离开时中止旧请求、停播并回收 objectURL,迟到的旧试听不出现",
|
||||
"读取并显示当前实际选择;应用成功后显示新声音并说明从下一次通话生效、已接通的通话不中途换声;换声音文案与请求均不触及名字/底色/关系/聊天/记忆;不读写通用助手状态",
|
||||
"失败如实:未配置/无通路/登记服务 503/TTS 503/422/409/断网/拒麦/麦克风占用/非安全来源/录音取消/停止/离开/重复提交/旧异步结果晚到各有中文说明;失败保留参考声音与已填内容;重复点击只发一次登记且不中止已发出的上传",
|
||||
"录音仅由用户点击开启、只请求音频不请求摄像头;停止、取消、切到其他分区、关闭设置、音轨中断后真实音轨全部 ended;打开分区本身只读列表、不申请麦克风;演示入口只显示说明卡、不挂载该组件(代码条件 real && open,未做演示入口浏览器测试)"
|
||||
],
|
||||
"deferred": [
|
||||
"真实 CosyVoice 试听、真实 FunASR 转写与克隆相似度、真实麦克风与真机(iPhone/Android/Safari)录音解码:留总工统一审核在获批环境与额度内实测,本卡零真实调用",
|
||||
"后端待补核项(总管已列给统一审核):真实 worker 通话开始读音色的时序、登记服务端成功后本地落盘失败/断连的半状态、ASR/试听实际用量与既有限额的衔接;前端不替后台修实现",
|
||||
"自定义音色删除、完整备份/恢复(CG-009/R6)后续卡;当前界面已写明暂不能在此删除",
|
||||
"交谈页未显示「本次通话所用声音」(POST /api/voice/session 的 voice 字段);如需在通话中提示,可后续小卡补",
|
||||
"设置「外接服务」分区仍沿旧文案显示语音识别/合成「尚未接通」,与本卡新分区及 HEL-878 语音接通不一致,未在本卡改动,交总管决定是否另行修正",
|
||||
"D1 最终音色决定仍归白栖知/总管;R5 整体真机验收与 R1–R7 完整要求继续承接,本卡交付不等于用户已验收音色"
|
||||
],
|
||||
"requirement_changes": [],
|
||||
"verification": [
|
||||
"web: tsc --noEmit 0 错;eslint src 0 错(仅既有 ChatPanel.tsx:240 警告,非本卡);vitest 137/137 通过(基线 118 + 本卡 19:WAV 编码/头校验、48k 立体声→16k 单声道、过短/静音/解不开/过大拒绝、API 合同与错误透传、离线零请求、allow_asr 规则、非 WAV 试听拒绝、中止的试听不返回结果、409/503、Recorder 仅点击开启/停止保留/取消丢弃/迟到授权立即关闭/20 秒自动停/音轨中断/拒绝与非安全来源/重复点击单开);vite build 通过",
|
||||
"浏览器:node tests/hel900_mock.mjs 8900 + node tests/hel900_shots.mjs <msedge.exe> <outDir> 8900,headless Edge + Chromium 假音频设备,83/83 通过;月光/雾光 × 电脑 1440×900/手机 390×844 主流程截图各 6 张及边界截图(文件上传、断网、登记 503、旧试听丢弃、409、拒麦、离开确认、未配置/无通路/服务不在)",
|
||||
"python -I scripts/check_requirements.py --handoff docs/requirements/handoff-HEL-900.json 通过;本运行环境无 git,--base-ref origin/main 比较未能执行,改以与 ce7279e 源码包逐文件哈希比对确认 docs/requirements 除新增本交接文件外零改动,--base-ref 检查留统一审核在仓库内执行",
|
||||
"未验证如实声明:假麦克风是浏览器内置提示音不是人声;试听是 mock 生成的音调不是 TTS;未接真实 8090/9880/FunASR,未部署,未触碰 HEL-879 现场与共享音色注册表,未访问 4080;Safari 与真机未测"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"baseline_version": "1.12",
|
||||
"read_commit": "d167ba927c1b07e4771219707c744e90051837d9",
|
||||
"task": "HEL-902:统一离线审核 HEL-900 前端(hel-900-preserved @ 701442d/37b4e69)与 HEL-899 后台(ce7279e),整合 HEL-879 真实窗口修复(hel-879-assembly @ be149cd)到独立分支 hel-902-integration,零真实调用、零部署、零依赖下载;并备齐真机补测申请包",
|
||||
"requirement_ids": ["CG-006", "CG-009", "CG-010", "CG-013", "CG-014", "CG-015", "CG-016", "CG-018", "CG-019", "CG-020", "CG-021", "VIS-003", "VIS-004", "VIS-008", "VIS-010", "UX-003", "UX-006", "AM-001", "GOV-001", "GOV-002", "GOV-003", "GOV-004", "GOV-005", "GOV-006", "DEL-001"],
|
||||
"deliverable": "独立整合分支 hel-902-integration(701442d+be149cd 无冲突合并,不改写母线/旧现场/PR#11);总工统一审核报告 docs/rework/hel902/REVIEW.md(含后台故障注入新增 tests/test_voice_review_hel902.py 6 用例:本地元数据落盘失败可恢复不逼重复注册、响应断连重试留可回收孤儿条目、开房 worker 写失败诚实 503、worker 状态损坏行为如实记录、流水写不进时应用 fail-closed 409、选择写失败整体回滚);真机补测申请包 docs/rework/hel902/r5-followup-package.md(时窗/逐类上限/停机方法/参考音频来源与 cg- 共享新增回收/旧服务保护/HEL-879 遗留量测并入);需求入口 README 基准行 v1.11→v1.12 勘误(授权非视觉小修,基准不回退)",
|
||||
"acceptance": [
|
||||
"统一 head 上实际复跑:pytest 376/376(370 基线+新增6)、verify_hel899_custom_voice.py 12/12、ruff src/tests/scripts 通过、需求检查 4/4(origin/main 与 ce7279e 各带/不带 handoff-HEL-900)",
|
||||
"前端保全独立复核:8 文件 blob SHA-256 与保全清单 8/8 一致;作者 ZIP 重下校验 SHA-256 一致;36 截图全部有效 PNG 且视口与 harness 定义一致;作者日志(vitest 137/137、lint 0错1既有警告、build、浏览器 83/83)与 handoff 声明逐项相符",
|
||||
"前端逐行静态复核与合同 §2/用户原话 01a17de1 一致:原始 WAV 字节+查询串、浏览器真转 16k mono PCM16、大小时长静音拒绝、allow_asr 显式门、试听必合法 WAV+canplay 后才可应用、参考原声与现场合成分开、请求代际清理、录音轨迹释放、演示入口不挂载零请求、CSS 仅用既有 token",
|
||||
"后台重点补核:capture→写 worker 文件→dispatch→worker 入口读一次的顺序锁定;共享注册表仅经 8090 且 cg- 命名空间不碰 11 支内置与通用助手状态;ASR/试听流水仅核算、硬闸仅 LLM/嵌入(如实,未称硬闸)",
|
||||
"问题清单集中一轮:🔴外接服务文案按实际能力改写(交视觉作者);🟡登记本地落盘失败映射文案、孤儿条目说明、worker 状态 docstring、会话页显示本次音色(结论:需要)、capture-dispatch 串行化;承接 CG-009/R6 删除与备份、R5 整体验收、R1–R7 完整功能"
|
||||
],
|
||||
"deferred": [
|
||||
"真实登记/可选 ASR 转写/真实试听/应用与下一通话验证、克隆相似度、真机(iPhone/Android/Safari)录音路径:待主卡批准补测包后执行,未批前真实 cap=0",
|
||||
"HEL-879 遗留:打断后约1秒停声毫秒级量测、文字打断语音方向、真实浏览器/设备麦克风路径——并入同一补测窗口,量测方法已写入补测包",
|
||||
"前端独立复跑(tsc/eslint/vitest/build/浏览器两主题×电脑/手机、演示入口零外发断言):本机依赖被清理且禁下载,需一次性 npm 同锁文件安装授权或随真机窗口在 .12 执行",
|
||||
"自定义音色删除、完整备份/恢复(CG-009/R6)后续卡;R5 整体验收与 R1–R7 完整功能持续承接;PR#4/PR#8 等仍无合并或替换正式界面授权"
|
||||
],
|
||||
"requirement_changes": [],
|
||||
"verification": [
|
||||
"pytest tests -q 376/376(py3.11.16 复用既有审核 venv,零安装)",
|
||||
"python -I scripts/verify_hel899_custom_voice.py 12/12;ruff check src tests scripts 通过",
|
||||
"python -I scripts/check_requirements.py --base-ref origin/main(及 --handoff docs/requirements/handoff-HEL-900.json、ce7279e 对照)4/4 通过",
|
||||
"前端与浏览器未在本机复跑(环境缺依赖且本卡禁下载安装),以作者日志+逐行静态复核+保全哈希复核作证据,如实标注未验证范围;真机项全部列入补测包"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"baseline_version": "1.12",
|
||||
"read_commit": "b09a907747f9836c4aea04016757321d28b7cb6b",
|
||||
"task": "HEL-904:HEL-902 统一审核后的后台有限返修(HEL-899 原作者)。三项:①登记在8090成功而本地元数据落盘失败→503中文映射(编号可恢复、共享登记不回滚、不逼重复登记),ASR流水先记再落盘;②worker状态文件损坏整体重写的实况补入docstring/合同,正常可读文件仍保留其他键;③修通话捕获音色与worker实读竞态:以会话不可变快照(通话窗口持有)保证响应voice=worker本通话实读声音、通话中改选只影响下一通,覆盖失败/取消/挂断失败转欠账/TTL到期结算,确定性Event门控无sleep;④补测申请材料收紧(仅材料不执行)。零真实调用、零部署、零下载、不动web/与共享worker、不新增依赖",
|
||||
"requirement_ids": ["CG-006", "CG-009", "CG-010", "CG-013", "CG-014", "CG-015", "CG-016", "CG-018", "CG-019", "CG-020", "CG-021", "AM-001", "GOV-001", "GOV-002", "GOV-003", "GOV-004", "GOV-005", "GOV-006", "DEL-001"],
|
||||
"deliverable": "独立分支(自b09a907)后台返修:custom.py登记失败映射LocalRecordFailed+ASR流水先记、write_worker_voice损坏实况docstring、通话持有hold/release+apply暂缓写、router捕获登记/失败取消释放/503映射/settle挂钩、session.py on_session_settled结算(挂断成功/转欠账/TTL到期);tests/test_voice_review_hel902.py第1例按新契约改写(含重启恢复与409守门断言)、新增tests/test_voice_rework_hel904.py确定性时序4例;合同docs/voice-custom-contract-HEL899.md §2.2/§2.5/§3更新;docs/rework/hel902/r5-followup-package.md收紧(head里程碑表:d167ba9=整合提交、b09a907=审核head、本卡head待统一复审登记,登记ASR与连续通话ASR区分、连续通话ASR计数手段与待补阻塞如实声明、停声量测单一时间基准帧级录音、参考音频明确D1包female_soft段含sha256/长度、回收清单与不未经确认保留测试垃圾、共享TTS启停快照恢复、git回退不代替共享回收、上限含失败口径与硬闸/监看界线);docs/rework/hel904/REWORK.md返修记录",
|
||||
"acceptance": [
|
||||
"登记成功+本地元数据写失败:503中文文案含编号、明确共享登记不回滚、刷新列表可找回并试听/应用、不逼重复登记(tests/test_voice_review_hel902.py改写例:含重启按编号label=编号继续用、新音色未试听409守门不放松、11支内置与通用助手零改写)",
|
||||
"worker状态文件损坏实况:docstring/合同如实注明整体重写仅剩voice,不再宣称任何情况下保留其他键;正常可读文件其他键保留(既有用例继续通过)",
|
||||
"竞态收口:确定性Event门控测试把worker读时点延迟到dispatch返回之后、并发应用新声音后——本通话worker读到=响应voice=旧音色;挂断结算后下一通capture用新声音;挂断失败转欠账、TTL到期、dispatch失败、请求取消四条路径都释放持有、应用随即写透;无sleep凑测试(tests/test_voice_rework_hel904.py 4例)",
|
||||
"补测材料:仅材料不执行,候选上限只收紧不放宽,一切失败/取消/重试/出站无响应计入口径;LLM/嵌入=程序硬闸与其余工程监看界线写明;连续通话ASR无程序计数手段处如实标待补阻塞;真实cap=0保持"
|
||||
],
|
||||
"deferred": [
|
||||
"真实登记/可选转写/真实试听/应用与下一通验证、克隆相似度、打断停声帧级量测、真机麦克风路径:待主卡批准补测包后执行,未批前真实cap=0",
|
||||
"本卡后台修复与前端另卡(外接服务文案、会话页显示本次音色)需原总工一次统一复审;通过后登记最终已验证head,此前任何head不得当作执行依据",
|
||||
"连续通话ASR分钟级音频时长与连接重试的程序计数手段:待补阻塞,窗口前由总管在.12验证LiveKit/worker侧指标可执行性,不通过则窗口不得启动含连续通话步骤",
|
||||
"前端同锁文件npm安装复跑:单独待批项,本轮不执行",
|
||||
"自定义音色删除、完整备份/恢复(CG-009/R6)后续卡;R5整体验收与R1-R7完整功能持续承接;本卡通过≠自定义音色用户验收,更≠完整产品完成"
|
||||
],
|
||||
"requirement_changes": [],
|
||||
"verification": [
|
||||
"pytest tests -q:380通过(基线376+新增4,py3.11.16复用既有venv零安装),全量含HEL-899 18项与总工故障注入全数通过",
|
||||
"python -I scripts/verify_hel899_custom_voice.py:12/12(含通话中改选定住本通话、下一通生效)",
|
||||
"ruff check src tests scripts:通过",
|
||||
"需求检查4/4:--base-ref origin/main 与 --base-ref b09a907 各带/不带本handoff全部通过",
|
||||
"未验证(如实):真实worker读时点、真实dispatch/房间、打断停声与真机路径——全部留在获批补测窗口;重叠通话不同音色的残余竞态如实记录于合同§2.5与REWORK.md,不宣称消除"
|
||||
]
|
||||
}
|
||||
@@ -14,5 +14,7 @@
|
||||
"dynamic-sample-effect-acceptance-20261023.md": "f5e9fde65a58ebc365de47569053ad7c30ce77ae82bb78773cc070e3cbffd90e",
|
||||
"comment-evidence-mature-reuse-20261025.json": "38ca076e26477e89cd161eaadb0fb00b0ee7bb5a26de2bd6ab41de52faaae79e",
|
||||
"mature-reuse-principle-20261025.md": "a2a75e071d3af5db722727bfaf8083bb60d07dcdd74e90d1e1374c1aafd2064d",
|
||||
"other-agent-discussion-20261025.txt": "42cd97029d73eace110e49e0566343dfeb25fe4f0633a10b78b126289938aaeb"
|
||||
"other-agent-discussion-20261025.txt": "42cd97029d73eace110e49e0566343dfeb25fe4f0633a10b78b126289938aaeb",
|
||||
"comment-evidence-full-experience-20261026.json": "75dd55b8755bdad217b44c3f516c9372b046aae06dff511527014c7b209eccff",
|
||||
"comment-evidence-custom-voice-20261027.json": "ed72bd78218e1c0b4ca644bf933d6bdb2e3aa8cd2c0333f3410f6b60845bd3cb"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
[
|
||||
{
|
||||
"id": "01a17de1-2892-78be-a422-eb6a11ffebfd",
|
||||
"author_type": "member",
|
||||
"author_id": "e5c6c938-db48-4ff9-954f-4fb8b063a132",
|
||||
"content": ".12已恢复,另外以上一条让我解压附件包试听,我不明白是什么意思,是让我听预设音色吗?如果是我觉得你的设计不够合理,我想要的是可以自定义音色,我的.12上安装的TTS是支持自定义音色的。至于最长2小时,3次通话的测试,我同意,音色你自己决定就行",
|
||||
"created_at": "2026-10-27T15:01:10Z",
|
||||
"parent_id": "01a17d45-f14e-7b62-9850-646e040c7318"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
[
|
||||
{
|
||||
"id": "01a17806-cb7e-76f3-8f3f-3f6360ddc668",
|
||||
"author_type": "member",
|
||||
"author_id": "e5c6c938-db48-4ff9-954f-4fb8b063a132",
|
||||
"content": "我听不懂你的意思,用大白话问我",
|
||||
"created_at": "2026-10-26T11:44:33Z",
|
||||
"parent_id": "01a174b3-867e-7a90-9628-e1abd82a71b7"
|
||||
},
|
||||
{
|
||||
"id": "01a1780e-6954-73ad-91da-3a5d81831a07",
|
||||
"author_type": "member",
|
||||
"author_id": "e5c6c938-db48-4ff9-954f-4fb8b063a132",
|
||||
"content": "我觉得这是工程问题,我不懂所以我无法抉择,但我知道截止目前,整个项目仅前端通过了我的审核,我没有现有的聊天和资料,也不存在真实或假聊天,因为一切都还没开始,我期望的是进行完整的项目体验,然后慢慢迭代,否则我根本不知道哪里是对的哪里是错的,你交由我决定的东西我认为是在原地打转或者说是在外围转圈而不是直奔核心",
|
||||
"created_at": "2026-10-26T11:52:52Z",
|
||||
"parent_id": "01a174b3-867e-7a90-9628-e1abd82a71b7"
|
||||
}
|
||||
]
|
||||
@@ -0,0 +1,60 @@
|
||||
# HEL-874 · 实际固定 Mem0 SDK 合同验证证据
|
||||
|
||||
运行脚本:`tools/verify_mem0_real_hel874.py`(仓库根,用 HEL-857 的固定 venv 执行;
|
||||
零真实出站——LLM 走 127.0.0.1 确定性假网关,嵌入用已有本地 fastembed 缓存,
|
||||
账本全部写在临时目录,不触权威三账)。
|
||||
|
||||
```bash
|
||||
/home/.../hel857-venv/bin/python tools/verify_mem0_real_hel874.py docs/rework/hel874/real-sdk-after.json
|
||||
```
|
||||
|
||||
固定安装事实(两份 JSON 的 `install` 字段):mem0ai 2.2.1、qdrant-client 1.20.0、
|
||||
fastembed 0.9.1;源码 tarball SHA256 `9dcef930…dda23` 与 HEL-857 记录一致;
|
||||
关键模块逐文件 SHA256 见 JSON。
|
||||
|
||||
## 结论(before = 31970c4 原适配层,after = 本卡修复后)
|
||||
|
||||
| 检查 | before | after | 事实 |
|
||||
| --- | --- | --- | --- |
|
||||
| C1 构造 | **失败** | 通过 | before 在同一路径开第二个 QdrantClient,固定 SDK 直接拒绝:`Storage folder … is already accessed by another instance of Qdrant client`——31970c4 的 mem0 模式根本起不来。after 复用 SDK 自带 `vector_store.client`,不再另开 client。 |
|
||||
| C2 add 锚点/作用域 | 无法到达 | 通过 | metadata(src_group/turn_roles/input_sha256)逐字落进 payload;`user_id` 作用域随 add 写入。 |
|
||||
| C2 每次真实开销 | 无法到达 | 通过 | 单行 add 实测 = 1 次提取 LLM + 2–3 条嵌入(phase1 查询嵌入 + phase3 提取批嵌入 + phase7 实体 upsert 嵌入),全部经包装记账。 |
|
||||
| C3 默认提取输入集 | 无法到达 | 通过 | 第二批 add 的提取提示实测包含第一批的提取记忆(旧记忆通道)与滚动 history——二者全部只来自此前过门批次,同一可证明输入集成立。 |
|
||||
| C3b 未分享 canary | 无法到达 | 通过 | 植入主档案的未分享伴侣行经 enqueue/tick 后不出现在任何出站 LLM 请求体,也不进任何锚点。 |
|
||||
| C4 search 过滤参数 | 无法到达 | 通过 | mem0 2.2.1 对无 `user_id` 过滤的 search 直接 `ValueError`(源码 main.py:1466 起);after 恒带 `filters={"user_id": …}`。`limit=` 形参在 2.2.1 被静默忽略,正确形参是 `top_k`。 |
|
||||
| C4 单次记账 | 无法到达 | 通过 | 每次 search 恰好 +1 条嵌入(before 设计上外层+包装双记,已在 fake-SDK 测试中证明并移除)。 |
|
||||
| C5 embed_cap=0 / llm_cap=0 | 无法到达 | 通过 | 任何真实工作前拒绝:假网关在此段收到 **0** 个请求;内部 LLM 现在过独立 llm_ops 闸(默认 0)。 |
|
||||
| C6 并发预占 | 无法到达 | 通过 | 8 路并发 search 对 cap=3 临时账,落账永不越 cap(BEGIN IMMEDIATE 预占)。 |
|
||||
| C7 关闭恢复 | 无法到达 | 通过 | aclose 后同目录重建实例,数据与锚点完好。 |
|
||||
|
||||
## 判定为真实缺陷并已修复的项(来源:固定安装源码核对 + 本脚本实跑复现)
|
||||
|
||||
1. 同路径双 QdrantClient → 构造即死(before JSON 的 trace)。
|
||||
2. 无过滤 search → 2.2.1 ValueError;`limit` 形参被忽略。
|
||||
3. search 外层+包装双记账。
|
||||
4. 内部提取 LLM 不过任何请求闸/账(embed 闸为 0 时也拦不住 LLM——本卡前
|
||||
LLM 先于嵌入扣账的说法不成立:实测 phase1 嵌入在前,但 LLM 从未被计入
|
||||
任何账)。
|
||||
5. 并发 check-then-debit 竞态可越 cap;失败/取消不回滚预占。
|
||||
|
||||
## 未发现问题的项(如实记录)
|
||||
|
||||
- 真实 fastembed `embed(text, memory_action)` / `embed_batch(texts, memory_action)`
|
||||
表面与适配层包装完全吻合(计数=落账)。
|
||||
- metadata 锚点在真实 qdrant payload 中逐字往返。
|
||||
- 滚动 history(save_messages 10 条窗)只含本产品此前 add 的原始消息。
|
||||
|
||||
## 勘正(HEL-882,2026-10-26,原文与前后 JSON 不改写)
|
||||
|
||||
本目录两份 JSON 的运行(e978e87 版脚本)**发生过真实本地嵌入推理**:脚本当时
|
||||
只把 LLM 换成 127.0.0.1 假网关,没有替换 fastembed 边界——`FastEmbedEmbedding`
|
||||
构造时加载了缓存模型,首条 add 即逐笔记了 3 笔真实向量推理
|
||||
(`embed_rows_after_first_add`)。因此提交信息与执行表中「零真实嵌入」的说法
|
||||
不成立;「零真实 LLM 请求/零下载/零非回环出站」仍成立。可证下限
|
||||
**≥12 条真实本地嵌入**(各分段合计,详见 `erratum-hel882.json`);精确总数因
|
||||
临时目录随任务沙箱清除不可恢复。权威三账未写、未补改。
|
||||
|
||||
自 HEL-882 起,`tools/verify_mem0_real_hel874.py` 在 `TextEmbedding` 构造前安装
|
||||
确定性 512 维向量替身(零模型加载、零真实嵌入),socket 层拒绝一切非回环连接
|
||||
(与总管独立复现口径一致),并在清理临时目录前把逐笔账写进证据 JSON
|
||||
(`final_embed_rows` / `final_llm_used`)。
|
||||
@@ -0,0 +1,46 @@
|
||||
{
|
||||
"card": "HEL-882",
|
||||
"kind": "evidence_erratum",
|
||||
"date": "2026-10-26",
|
||||
"subject": "HEL-874 真实 SDK 验证的嵌入证据口径勘正(原 JSON 一律不改写)",
|
||||
"incorrect_claims": [
|
||||
{
|
||||
"location": "git commit e978e878dfc34f38c781d48f87b93dc21bbf8a61 提交信息",
|
||||
"claim": "zero real model calls, zero real embeddings, zero outbound (fake gateway on loopback + existing local model cache only)",
|
||||
"fact": "LLM 确为零真实请求(全部打在 127.0.0.1 假网关);但嵌入并非零——脚本只替换了 LLM 网关,未替换 fastembed 边界,FastEmbedEmbedding.__init__ 加载了缓存模型并做了真实本地向量推理",
|
||||
"correction": "应为:零真实 LLM 请求、零出站连接、存在真实本地嵌入推理(见 evidence_recovery 的可证下限)"
|
||||
},
|
||||
{
|
||||
"location": "docs/budget-plan-hel874.md 首段(e978e87 版)",
|
||||
"claim": "本卡(HEL-874)零真实模型调用、零真实嵌入、零出站(真实 SDK 验证全部走本地确定性替身与本地模型缓存)",
|
||||
"fact": "『本地模型缓存』那半句与『零真实嵌入』互相矛盾:读取缓存做推理就是真实嵌入,只是零下载、零出站",
|
||||
"correction": "本卡(HEL-882 版)已改写为:零真实模型调用、零真实嵌入(确定性 512 维替身)、零非回环连接"
|
||||
},
|
||||
{
|
||||
"location": "docs/requirements/handoff-HEL-874.json verification/deliverable 字段",
|
||||
"claim": "全部零真实模型/零嵌入/零出站(127.0.0.1 确定性假网关与本地模型缓存除外)",
|
||||
"fact": "『除外』条款实际承认了本地模型缓存的使用,但『零嵌入』表述优先读作零嵌入推理,与事实不符",
|
||||
"correction": "handoff 为历史交接记录不改写;以本勘正为准"
|
||||
}
|
||||
],
|
||||
"evidence_recovery": {
|
||||
"recoverable": [
|
||||
"docs/rework/hel874/real-sdk-after.json: embed_rows_after_first_add 共 3 笔(product:search / product:batch:add / product:add),即首条 add 发生 3 次真实本地嵌入推理",
|
||||
"同 JSON C2_add_ledger_shape: embed_items=3 llm_calls=1(第二条为逐笔明细佐证)",
|
||||
"同 JSON C3_extraction_input_set: 第二条 add 成功 → 按同一流程至少再 2 笔(查询嵌入+提取批嵌入,实体 upsert 0..N 不确定)",
|
||||
"同 JSON C3b_unshared_canary_never_outbound: queued_public_batches=2,tick 处理 1 个批次 → 至少再 2 笔",
|
||||
"同 JSON C4_search_single_debit: embed_delta=1",
|
||||
"同 JSON C6_concurrency_cap: used=3(独立 conc 临时账,同为真实推理)",
|
||||
"同 JSON C7_reopen_after_close: 重开后的 search → +1 笔"
|
||||
],
|
||||
"lower_bound_real_local_embeddings": 12,
|
||||
"upper_bound_estimate": 14,
|
||||
"unrecoverable": [
|
||||
"精确总数不可恢复:脚本临时目录 /tmp/multica-task-4220825970/hel874-real-sdk-*(含逐笔临时账)已随任务沙箱清除,仓库内只留有上述分段 JSON"
|
||||
],
|
||||
"llm_requests": "全部为 127.0.0.1 确定性假网关(gateway_requests_total=3,零真实 LLM 请求,此口径原判断正确,无需勘正)",
|
||||
"downloads_and_outbound": "零下载、零非回环出站(模型缓存为既有只读复用),此口径原判断正确"
|
||||
},
|
||||
"authoritative_ledgers": "权威三账(真实请求 39/60、嵌入 498/500、HEL-835 闸)全程未写、未补改;临时账全部在已清除的临时目录,与权威账无关",
|
||||
"fix_in_this_card": "tools/verify_mem0_real_hel874.py 自本版本起在 TextEmbedding 构造前安装确定性 512 维向量替身(零模型加载)且 socket 拒绝一切非回环连接(总管独立复现同口径);证据 JSON 增记 final_embed_rows/final_llm_used 并在清理临时目录前落盘,避免同类不可恢复"
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
{
|
||||
"started": "2026-10-26T14:02:45Z",
|
||||
"install": {
|
||||
"python": "3.10.12",
|
||||
"mem0ai": "2.2.1",
|
||||
"qdrant-client": "1.20.0",
|
||||
"fastembed": "0.9.1",
|
||||
"mem0_path": "/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-857-2cf6dc7dfc87/workdir/hel857-venv/lib/python3.10/site-packages/mem0",
|
||||
"module_sha256": {
|
||||
"memory/main.py": "f329ca4a17af1fbefb32ac10d4cc7ae7ddbdb7435a87eb74c30915cff98b8b7c",
|
||||
"memory/storage.py": "5f5ecdadd2b260fd14f36a0f338336eb760275465dd1056a99a47e1ef07702bd",
|
||||
"embeddings/fastembed.py": "3ec2ae87df5d0bebedb8b5471366c3412975847458499f66097f7b8c9ac8c9b8",
|
||||
"llms/openai.py": "37e6d3c22b55df0731740f4e0868b95bd480ce44363227fe53461db328c5f67e",
|
||||
"vector_stores/qdrant.py": "da570579d5cad69e6f123fdfe32b725235a25604e70047666bec763ba6e2bf43"
|
||||
},
|
||||
"source_tarball_sha256": "9dcef9303ebcec116eec6739f01b8b35bd24459de6a569686b4d19b9412dda23"
|
||||
},
|
||||
"adapter_has_llm_guard": true,
|
||||
"checks": [
|
||||
{
|
||||
"name": "C1_construct",
|
||||
"ok": true,
|
||||
"detail": "client_path=sdk-vector-store-client"
|
||||
},
|
||||
{
|
||||
"name": "C2_add_anchor_payload",
|
||||
"ok": true,
|
||||
"detail": "created=True payload_keys=['created_at', 'data', 'hash', 'input_sha256', 'src_group', 'text_lemmatized', 'turn_ids', 'turn_roles']"
|
||||
},
|
||||
{
|
||||
"name": "C2_add_user_scope",
|
||||
"ok": true,
|
||||
"detail": "user_id present in stored payload"
|
||||
},
|
||||
{
|
||||
"name": "C2_add_ledger_shape",
|
||||
"ok": true,
|
||||
"detail": "embed_items=3 llm_calls=1"
|
||||
},
|
||||
{
|
||||
"name": "C3_extraction_input_set",
|
||||
"ok": true,
|
||||
"detail": "old_memory=True new_row=True history_carry=True"
|
||||
},
|
||||
{
|
||||
"name": "C3b_unshared_canary_never_outbound",
|
||||
"ok": true,
|
||||
"detail": "queued_public_batches=2 leaked=False anchor_taint=False"
|
||||
},
|
||||
{
|
||||
"name": "C4_search_filters",
|
||||
"ok": true,
|
||||
"detail": "hits=3"
|
||||
},
|
||||
{
|
||||
"name": "C4_search_single_debit",
|
||||
"ok": true,
|
||||
"detail": "embed_delta=1 (pre-fix=2)"
|
||||
},
|
||||
{
|
||||
"name": "C6_concurrency_cap",
|
||||
"ok": true,
|
||||
"detail": "outcomes=['ok', 'refused'] used=3 cap=3"
|
||||
},
|
||||
{
|
||||
"name": "C7_reopen_after_close",
|
||||
"ok": true,
|
||||
"detail": "hits_after_reopen=3"
|
||||
},
|
||||
{
|
||||
"name": "C5_embed_zero_refuses",
|
||||
"ok": true,
|
||||
"detail": "err=semantic_embed_budget_not_approved llm_sent=0"
|
||||
},
|
||||
{
|
||||
"name": "C5_llm_zero_refuses",
|
||||
"ok": true,
|
||||
"detail": "err=semantic_llm_budget_not_approved llm_sent=0"
|
||||
}
|
||||
],
|
||||
"embed_rows_after_first_add": [
|
||||
{
|
||||
"kind": "dense",
|
||||
"items": 1,
|
||||
"note": "product:search"
|
||||
},
|
||||
{
|
||||
"kind": "dense",
|
||||
"items": 1,
|
||||
"note": "product:batch:add"
|
||||
},
|
||||
{
|
||||
"kind": "dense",
|
||||
"items": 1,
|
||||
"note": "product:add"
|
||||
}
|
||||
],
|
||||
"finished": "2026-10-26T14:02:47Z",
|
||||
"gateway_requests_total": 3,
|
||||
"failures": []
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"started": "2026-10-26T14:02:48Z",
|
||||
"install": {
|
||||
"python": "3.10.12",
|
||||
"mem0ai": "2.2.1",
|
||||
"qdrant-client": "1.20.0",
|
||||
"fastembed": "0.9.1",
|
||||
"mem0_path": "/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-857-2cf6dc7dfc87/workdir/hel857-venv/lib/python3.10/site-packages/mem0",
|
||||
"module_sha256": {
|
||||
"memory/main.py": "f329ca4a17af1fbefb32ac10d4cc7ae7ddbdb7435a87eb74c30915cff98b8b7c",
|
||||
"memory/storage.py": "5f5ecdadd2b260fd14f36a0f338336eb760275465dd1056a99a47e1ef07702bd",
|
||||
"embeddings/fastembed.py": "3ec2ae87df5d0bebedb8b5471366c3412975847458499f66097f7b8c9ac8c9b8",
|
||||
"llms/openai.py": "37e6d3c22b55df0731740f4e0868b95bd480ce44363227fe53461db328c5f67e",
|
||||
"vector_stores/qdrant.py": "da570579d5cad69e6f123fdfe32b725235a25604e70047666bec763ba6e2bf43"
|
||||
},
|
||||
"source_tarball_sha256": "9dcef9303ebcec116eec6739f01b8b35bd24459de6a569686b4d19b9412dda23"
|
||||
},
|
||||
"adapter_has_llm_guard": false,
|
||||
"checks": [
|
||||
{
|
||||
"name": "C1_construct",
|
||||
"ok": false,
|
||||
"detail": "RuntimeError: Storage folder /tmp/multica-task-4220825970/hel874-real-sdk-3tml6wtr/vec/vec_public is already accessed by another instance of Qdrant client. If you require concurrent access, use Qdrant server instead."
|
||||
}
|
||||
],
|
||||
"trace": "Traceback (most recent call last):\n File \"/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-857-2cf6dc7dfc87/workdir/hel857-venv/lib/python3.10/site-packages/portalocker/portalocker.py\", line 1008, in lock\n self.locker(fd, flags)\nBlockingIOError: [Errno 11] Resource temporarily unavailable\n\nThe above exception was the direct cause of the following exception:\n\nTraceback (most recent call last):\n File \"/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-857-2cf6dc7dfc87/workdir/hel857-venv/lib/python3.10/site-packages/qdrant_client/local/qdrant_local.py\", line 178, in _load\n portalocker.lock(\n File \"/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-857-2cf6dc7dfc87/workdir/hel857-venv/lib/python3.10/site-packages/portalocker/portalocker.py\", line 1151, in lock\n _posix_locker_instance.lock(file, flags)\n File \"/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-857-2cf6dc7dfc87/workdir/hel857-venv/lib/python3.10/site-packages/portalocker/portalocker.py\", line 1011, in lock\n raise exceptions.AlreadyLocked(\nportalocker.exceptions.AlreadyLocked: (BlockingIOError(11, 'Resource temporarily unavailable'), '[Errno 11] Resource temporarily unavailable')\n\nDuring handling of the above exception, another exception occurred:\n\nTraceback (most recent call last):\n File \"/tmp/multica-task-4220825970/opencode/before-31970c4/tools/verify_mem0_real_hel874.py\", line 222, in main_async\n backend = Mem0Backend(config_for(tmp, ledger, port=port, cap=64, llm_cap=32))\n File \"/tmp/multica-task-4220825970/opencode/before-31970c4/src/cybergril/memory/semantic.py\", line 163, in __init__\n self._memory = Memory.from_config(\n File \"/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-857-2cf6dc7dfc87/workdir/hel857-venv/lib/python3.10/site-packages/mem0/memory/main.py\", line 737, in from_config\n return cls(config)\n File \"/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-857-2cf6dc7dfc87/workdir/hel857-venv/lib/python3.10/site-packages/mem0/memory/main.py\", line 496, in __init__\n self.vector_store = VectorStoreFactory.create(\n File \"/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-857-2cf6dc7dfc87/workdir/hel857-venv/lib/python3.10/site-packages/mem0/utils/factory.py\", line 216, in create\n return vector_store_instance(**config)\n File \"/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-857-2cf6dc7dfc87/workdir/hel857-venv/lib/python3.10/site-packages/mem0/vector_stores/qdrant.py\", line 81, in __init__\n self.client = QdrantClient(**params)\n File \"/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-857-2cf6dc7dfc87/workdir/hel857-venv/lib/python3.10/site-packages/qdrant_client/qdrant_client.py\", line 130, in __init__\n self._client = QdrantLocal(\n File \"/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-857-2cf6dc7dfc87/workdir/hel857-venv/lib/python3.10/site-packages/qdrant_client/local/qdrant_local.py\", line 91, in __init__\n self._load()\n File \"/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-857-2cf6dc7dfc87/workdir/hel857-venv/lib/python3.10/site-packages/qdrant_client/local/qdrant_local.py\", line 183, in _load\n raise RuntimeError(\nRuntimeError: Storage folder /tmp/multica-task-4220825970/hel874-real-sdk-3tml6wtr/vec/vec_public is already accessed by another instance of Qdrant client. If you require concurrent access, use Qdrant server instead.\n",
|
||||
"finished": "2026-10-26T14:02:49Z",
|
||||
"gateway_requests_total": 0,
|
||||
"failures": [
|
||||
"C1_construct: RuntimeError: Storage folder /tmp/multica-task-4220825970/hel874-real-sdk-3tml6wtr/vec/vec_public is already accessed by another instance of Qdrant client. If you require concurrent access, use Qdrant server instead."
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 438 KiB |
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"ok": true,
|
||||
"checks": 9,
|
||||
"fail_count": 0,
|
||||
"netguard": {
|
||||
"guard_loaded": true,
|
||||
"nonloopback_connect_attempts": 0,
|
||||
"nonloopback_dns_lookups": 0,
|
||||
"rejected": []
|
||||
},
|
||||
"service_epoch_isolation": "CYBERGRIL_MODELS loopback, caps 0, socket guard rejecting non-loopback"
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 441 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 447 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 350 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 447 KiB |
@@ -0,0 +1,47 @@
|
||||
# HEL-879 · D1 参考试听包(零合成,已交付)
|
||||
|
||||
> 交付时间 2026-10-27。性质:把服务器既有 11 支音色的 zero-shot 参考录音整理成
|
||||
> 可离线播放的 HTML 试听页 + 音频包,作为主卡 D1 拍板材料。**零 TTS 合成、零
|
||||
> 克隆、零共享音色切换、零下载安装**;对 .12 只做 SSH 只读复制,未改服务器任何
|
||||
> 文件与状态。
|
||||
>
|
||||
> **2026-10-27 勘误(主卡授权轮)**:白栖知反馈「让我解压附件包试听」的设计
|
||||
> 不合理(主卡评论 `01a17de1-2892-78be-a422-eb6a11ffebfd`)——他要的是可
|
||||
> 自定义音色,而不是从预设音色里挑一个。本包正名为「**非定制功能入口**」:
|
||||
> 它只是既有 11 支登记音色的参考原声对照材料,**不是**用户音色定制/上传/录制
|
||||
> 的功能入口;正式的自定义音色(上传、录制、试听、应用)由独立施工分支接续,
|
||||
> 未完成前不宣称可用。本轮 R5 有限测试由总管选定临时测试音色 `female_soft`
|
||||
> (已核服务器登记;临时测试值,不是用户最终音色),不要求用户解压本包选 ID。
|
||||
|
||||
## 包内容(随本卡评论附件交付,不入仓库大媒体)
|
||||
|
||||
`HEL-879-D1-参考试听包.zip`(4.4MB,sha256
|
||||
`e20764f9f98cbfac5ef966227540a75c5061cf16d151e5d0c9d86b620e3972f9`):
|
||||
|
||||
- `index.html` —— 离线试听页(自包含,无外部依赖;解压后直接用浏览器打开),
|
||||
逐支列出音色 ID、时长/采样率、参考录音原文、播放器、文件哈希前缀;
|
||||
页首明确注明「参考录音 ≠ 实际合成效果」。
|
||||
- `manifest.json` —— 机器可读清单:11 支音色的 id / 文件 / prompt_text /
|
||||
服务器源路径 / sha256 / 字节数 / 秒数 / 采样率 / 声道(本目录留有同内容副本)。
|
||||
- `voice_samples/*.wav` —— 11 段参考录音原文件。
|
||||
|
||||
## 来源与取回方式(可复核)
|
||||
|
||||
- 音色登记:`192.168.200.12:/opt/voice-agent/cosyvoice/voices.json`(实读,
|
||||
11 个 ID:bailu、bajie、default、female_soft、haimianbaobao、jiaojiao、
|
||||
male_warm、nezha、rain、sunwukong、xiaoyun;每项 `prompt_wav` + `prompt_text`)。
|
||||
- 音频文件:`prompt_wav` 所指 wav(`voice_samples/<id>.wav` 10 支 +
|
||||
default 用 `CosyVoice/asset/zero_shot_prompt.wav`),`scp` 只读取回。
|
||||
- 完整性:每文件本地 sha256 与服务器 `sha256sum` 输出逐一相符(见
|
||||
manifest.json;default 为 IEEE float32/24kHz/3.5s,bailu 为 44.1kHz 立体声
|
||||
10s,其余 16k/32k 单声道 2.4–16.8s)。
|
||||
|
||||
## 边界(如实)
|
||||
|
||||
- 参考录音是各音色**来源说话人的真实录音**(zero-shot 克隆依据),不是
|
||||
CosyVoice 实际合成产物;实际合成效果与参考录音不同,需在获批测试窗口内
|
||||
真实合成复核(计入 TTS 预算)。
|
||||
- 参考录音原文为各来源录音本身的内容,按原样保留,仅作试听对照;其中数支
|
||||
为影视/角色向来源,是否适合「她」由白栖知试听后判断,工程不代选、不预筛。
|
||||
- 通用演示当前 `voice_state.json` = rain 是共享演示状态,不是本用户的选择依据。
|
||||
- 克隆新音色需写共享 `voices.json` 并触发共享 TTS 热加载,**需单独授权**,本包未做。
|
||||
@@ -0,0 +1,135 @@
|
||||
{
|
||||
"package": "HEL-879 D1 参考试听包(零合成)",
|
||||
"generated": "2026-10-27",
|
||||
"source_server": "192.168.200.12 (SSH 只读取回,未改服务器任何文件)",
|
||||
"source_registry": "/opt/voice-agent/cosyvoice/voices.json",
|
||||
"count": 11,
|
||||
"notes": [
|
||||
"参考录音 = 该音色 zero-shot 克隆的来源录音(音色来源说话人的真实录音),不是 CosyVoice 实际合成产物;实际合成效果与参考录音不同,需在获批测试窗口内真实合成复核(计入 TTS 预算)。",
|
||||
"通用演示当前使用 rain,是共享演示状态,不是本用户的选择依据。",
|
||||
"本包只读取得,未切换/修改任何共享音色状态;克隆需另行单独授权。"
|
||||
],
|
||||
"voices": [
|
||||
{
|
||||
"id": "default",
|
||||
"file": "voice_samples/zero_shot_prompt.wav",
|
||||
"prompt_text": "希望你以后能够做的比我还好呦。",
|
||||
"server_prompt_wav": "/opt/voice-agent/cosyvoice/CosyVoice/asset/zero_shot_prompt.wav",
|
||||
"sha256": "c7b31d6dbe7cc6a716dded00550db5b50940bf209e424e4ad207b12e657c8ff6",
|
||||
"bytes": 334138,
|
||||
"seconds": 3.5,
|
||||
"sample_rate": 24000,
|
||||
"channels": 1
|
||||
},
|
||||
{
|
||||
"id": "sunwukong",
|
||||
"file": "voice_samples/sunwukong.wav",
|
||||
"prompt_text": "俺老孙来也,俺乃500年前大闹天宫的齐天大圣孙悟空,这里山势险峻,只怕藏有妖精妖怪,哪里逃吃?俺老孙吧。",
|
||||
"server_prompt_wav": "/opt/voice-agent/cosyvoice/voice_samples/sunwukong.wav",
|
||||
"sha256": "a0cf44a8ab659ebddb8bc4faffe88f717d14d2c66c09bc5ea657212826806e68",
|
||||
"bytes": 429746,
|
||||
"seconds": 13.4,
|
||||
"sample_rate": 16000,
|
||||
"channels": 1
|
||||
},
|
||||
{
|
||||
"id": "nezha",
|
||||
"file": "voice_samples/nezha.wav",
|
||||
"prompt_text": "天雷滚滚,我好怕怕劈的我浑身掉渣渣,突破天劫,我笑,哈哈逆天改命。我吹喇叭滴答滴答,滴滴答。",
|
||||
"server_prompt_wav": "/opt/voice-agent/cosyvoice/voice_samples/nezha.wav",
|
||||
"sha256": "9911a73e3f54c235dedb05c18f29356f41ba3b1e1b58811c4f766897f0fe1d10",
|
||||
"bytes": 305196,
|
||||
"seconds": 9.5,
|
||||
"sample_rate": 16000,
|
||||
"channels": 1
|
||||
},
|
||||
{
|
||||
"id": "bajie",
|
||||
"file": "voice_samples/bajie.wav",
|
||||
"prompt_text": "师傅,哎,这取经路比高,老庄种地还苦,俺老猪饿的能吞下石龙素包子,猴哥,你筋斗云块,要不先去画个圆。",
|
||||
"server_prompt_wav": "/opt/voice-agent/cosyvoice/voice_samples/bajie.wav",
|
||||
"sha256": "1f9c84ce8c10145ace5f615a428a08e2482f322363f037245878068aa95ed98a",
|
||||
"bytes": 424320,
|
||||
"seconds": 13.3,
|
||||
"sample_rate": 16000,
|
||||
"channels": 1
|
||||
},
|
||||
{
|
||||
"id": "haimianbaobao",
|
||||
"file": "voice_samples/haimianbaobao.wav",
|
||||
"prompt_text": "没错,我就是个笨蛋派大星,我们一起去抓水母吧,我们一起度过快乐的一天。",
|
||||
"server_prompt_wav": "/opt/voice-agent/cosyvoice/voice_samples/haimianbaobao.wav",
|
||||
"sha256": "c60912dfccd76390baa921d4c99b0120f528837608964290e96cad1221da9c9d",
|
||||
"bytes": 228726,
|
||||
"seconds": 7.1,
|
||||
"sample_rate": 16000,
|
||||
"channels": 1
|
||||
},
|
||||
{
|
||||
"id": "female_soft",
|
||||
"file": "voice_samples/female_soft.wav",
|
||||
"prompt_text": "这点我说一下,就是因为那个就是摩根豪泽尔这本儿金钱心理学。其实在我们这行业里也算一本很有名名的书了。就我之前也读过。然后你说到这点啊,让我想起来他这本书里还挺。",
|
||||
"server_prompt_wav": "/opt/voice-agent/cosyvoice/voice_samples/female_soft.wav",
|
||||
"sha256": "4a65d17099239711601cb17e28b7aa7b6149acd153b92fd0366c23902bd4f687",
|
||||
"bytes": 341192,
|
||||
"seconds": 10.7,
|
||||
"sample_rate": 16000,
|
||||
"channels": 1
|
||||
},
|
||||
{
|
||||
"id": "male_warm",
|
||||
"file": "voice_samples/male_warm.wav",
|
||||
"prompt_text": "um a while we built eight hype looe test track adjacent to space acts just for a student competition。 um to encourage intiative ideas in transport and actually ends up being the the biggest um vacuum chamber in the world after the launch。 haveringcollider。",
|
||||
"server_prompt_wav": "/opt/voice-agent/cosyvoice/voice_samples/male_warm.wav",
|
||||
"sha256": "2c4109b2d685e1923ed66433eb08c92047a1f67510629a27edf49af4e5c606dd",
|
||||
"bytes": 539032,
|
||||
"seconds": 16.8,
|
||||
"sample_rate": 16000,
|
||||
"channels": 1
|
||||
},
|
||||
{
|
||||
"id": "xiaoyun",
|
||||
"file": "voice_samples/xiaoyun.wav",
|
||||
"prompt_text": "盯着你看怎么啦,难得看你这么有意思的样子嘛",
|
||||
"server_prompt_wav": "/opt/voice-agent/web/../cosyvoice/voice_samples/xiaoyun.wav",
|
||||
"sha256": "6ad3ca7a6f1d9ddd10c5647338200fc9913f7adc71d8495a61b6b8e18eadc87e",
|
||||
"bytes": 297004,
|
||||
"seconds": 4.6,
|
||||
"sample_rate": 32000,
|
||||
"channels": 1
|
||||
},
|
||||
{
|
||||
"id": "rain",
|
||||
"file": "voice_samples/rain.wav",
|
||||
"prompt_text": "你是不是早就想睡我了呀",
|
||||
"server_prompt_wav": "/opt/voice-agent/web/../cosyvoice/voice_samples/rain.wav",
|
||||
"sha256": "37db24611b999f2f2328fa19c5c6e26117b5ec5d3d2037068af2fc12c6ad25ba",
|
||||
"bytes": 152364,
|
||||
"seconds": 2.4,
|
||||
"sample_rate": 32000,
|
||||
"channels": 1
|
||||
},
|
||||
{
|
||||
"id": "jiaojiao",
|
||||
"file": "voice_samples/jiaojiao.wav",
|
||||
"prompt_text": "怎么还有没射的啊,是我不够努力吗",
|
||||
"server_prompt_wav": "/opt/voice-agent/web/../cosyvoice/voice_samples/jiaojiao.wav",
|
||||
"sha256": "6db2b2de2d59e22bb0badbb1a6325d68885eda409ad63f5941e5ccad6486fc9f",
|
||||
"bytes": 301484,
|
||||
"seconds": 4.7,
|
||||
"sample_rate": 32000,
|
||||
"channels": 1
|
||||
},
|
||||
{
|
||||
"id": "bailu",
|
||||
"file": "voice_samples/bailu.wav",
|
||||
"prompt_text": "烈火军校啊,招摇啊这种类型,我都是那种比较……呃……豪爽,比较开朗的那种类型,阳光大女孩儿,那种感觉",
|
||||
"server_prompt_wav": "/opt/voice-agent/web/../cosyvoice/voice_samples/bailu.wav",
|
||||
"sha256": "3fbc0aff09118a9bc10bae87a837e6a3de6a30268c6ee01c727b56c49aecd26d",
|
||||
"bytes": 1769550,
|
||||
"seconds": 10.0,
|
||||
"sample_rate": 44100,
|
||||
"channels": 2
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,124 @@
|
||||
# HEL-879 · R5 有限真实语音测试窗口记录(2026-10-27)
|
||||
|
||||
> 授权:白栖知主卡评论 `01a17de1-2892-78be-a422-eb6a11ffebfd`(同意最长 2 小时 /
|
||||
> 3 次通话;音色由工程自定);额度沿《r5-test-package.md》§6 申请上限执行。
|
||||
> 窗口(UTC):**15:26:54 – 15:58:10**(31 分 16 秒,未用满 2 小时)。
|
||||
> 候选 `hel-879-assembly` @ `8dc84f8`;模型/运行时/认证与既有实例一致(同一
|
||||
> `192.168.200.11:8731` halogen 端点),零新增付费支出。
|
||||
|
||||
## 1. 部署布局(全部独立,已全部撤除)
|
||||
|
||||
| 组件 | 端口/路径 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 统一实例(同进程双入口) | HTTP 8360 + HTTPS 8361 | `deploy/voice/serve_dual_8360_8361.py`,隔离数据 `/opt/cybergril-hel879/data/`;`.venv311`+uv CPython 3.11.16 自本机离线复制(.12 无 uv/node,零下载) |
|
||||
| WSS TLS 桥 | 8363 → 127.0.0.1:7880 | `deploy/voice/wss_bridge.example.py`,与 8361 同一张自签证书 |
|
||||
| 专属 worker | 健康口 8082 | `/opt/voice-agent-cybergril/`,复用 agent venv(livekit-agents 1.8.8),`voice_state_cybergril.json` = `female_soft`(临时测试值;未写通用助手 `voice_state.json`/`voices.json`) |
|
||||
| 共享 TTS(CosyVoice) | 9880 | 窗口内从停机恢复;结束时核实无他人占用后按窗口前状态停回 |
|
||||
| 测试档案 | — | 隔离实例自建测试伴侣(名字「小测」),非用户真实档案 |
|
||||
|
||||
配置差异(均记录在案、可回滚):`models.yaml` 预算写入本轮批准值
|
||||
(dialogue 40、total 40/500k,其余类别 0);`CYBERGRIL_SEMANTIC=stub`(嵌入 0);
|
||||
`CYBERGRIL_R2_ENABLED=1`(receipt 签发依赖生活运行时开启;life/background 预算
|
||||
仍为 0,实测无后台模型调用);`voice.yaml` `session_ttl_seconds: 900`
|
||||
(真实验证 TTL 到期删房用;仓库默认 7200)。
|
||||
|
||||
## 2. 真机发现并修复的代码问题(有限返工,含证据)
|
||||
|
||||
1. **Twirp 服务 token 缺少端点授权(401)**:`livekit_wire.mint_server_token`
|
||||
原按「无 grants 形态」铸造,但已装 SDK 的 `create_dispatch` 以
|
||||
`VideoGrants(room_admin=True, room=…)` 签名、`delete_room` 以
|
||||
`VideoGrants(room_create=True)` 签名;真机 LiveKit 拒绝无授权 bearer(401)。
|
||||
离线期 8 项 SDK 检查只比对了 token 形态,未对真服务器发送,未暴露此问题。
|
||||
修复:`mint_server_token` 增加 `video` grants 参数,两处调用按 SDK 同款授权。
|
||||
2. **protobuf 响应不可解析**:CreateDispatch 以 `application/protobuf` 请求时
|
||||
服务器回二进制,原实现的 `json.loads` 崩溃。修复:改走 Twirp JSON
|
||||
(`application/json`),零新依赖,dispatch id 正常解析;离线替身同步改为
|
||||
JSON 断言(`tests/test_voice_session.py`、`tests/test_voice_rework_hel879.py`)。
|
||||
3. **自签证书 `CA:TRUE` 被 rustls 拒绝**:openssl 默认给自签证书加了
|
||||
`basicConstraints=CA:TRUE`,livekit 客户端(rustls)报 `CaUsedAsEndEntity`。
|
||||
重签为 `critical,CA:FALSE` + `SAN=IP:192.168.200.12` 后通过;测试客户端以
|
||||
`SSL_CERT_FILE` 进程级信任该证书(非系统信任库、非浏览器例外冒充)。
|
||||
|
||||
修复后全量 `pytest tests -q` **352/352** 通过、ruff(src/tests/scripts)0 错;
|
||||
本文件与修复随本轮提交入库。
|
||||
|
||||
## 3. 验证结果
|
||||
|
||||
真链:预录参考录音(**音频回放,非用户设备麦克风/手机**)→ 真实 WebRTC →
|
||||
LiveKit 7880(客户端经 8363 WSS 桥)→ FunASR 流式识别 → 统一 `POST /api/chat`
|
||||
(真 LLM)→ CosyVoice 合成(female_soft)→ WebRTC 回流收音(48k WAV 落盘)。
|
||||
|
||||
| 项 | 结果 | 证据 |
|
||||
| --- | --- | --- |
|
||||
| 连续 ≥3 轮(同档案、同对话源、音色一致) | ✅ 通话2:haimianbaobao/nezha/rain 三轮全部 `turn_end`;跨通话记忆延续可见(通话2 回复接住通话1 话题) | `call1b.subtitles.jsonl`、`chat_message` 全表 |
|
||||
| 完整播放 receipt | ✅ 总管收尾独立复核:最终库及一致性快照均为 **8 条** `sharing_attempt`,全部 `ack_at` 落值、state=judged;取消用户轮 msg7/msg23 对应回执均为0。原交付4条是较早阶段数字,不能代表最终库 | 只读SQL与快照恢复核对;`/api/chat/received 200` |
|
||||
| 开口打断 | ✅(发生真实性)通话1 三次真实 `turn_cancel(interrupted)`,用户开口截断在播回复、旧轮 user 行标 cancelled;**精确 ~1s 停声计时未取得**(量测设计缺陷+后两轮回复过短无以复测,见 §5) | `call1.subtitles.jsonl` seq68/87/92 |
|
||||
| 软件客户端挂断清理 | ✅ DELETE 200 → 房间真实删除(ListRooms 空)、删除后仅 2 帧在途(约20ms)、软件客户端 track 停发;**不代表用户设备麦克风指示灯或扬声器残音已验** | `call1b.json hangup` |
|
||||
| 断线(不挂断)+ TTL 到期后台删房 | ✅ 掉线不删 → 会话过期自动转债删除;15:52/15:56/15:57 三笔全部结清,账本空、房间空 | 轮询记录(窗口观察) |
|
||||
| API 重启清理 | ✅ 重启 epoch 4→5、档案/历史完整、voice 配置在;重启遗留会话按 TTL 由补偿清理全部结清 | 同上 |
|
||||
| 文字/语音互斥 | ✅(机制)文字轮被后到语音轮取消(msg23=cancelled)——同一把 chat 锁双向互斥成立;**「文字打断语音」方向未单独取证**(触发时机竞态,见 §5) | `call3.json`、消息表 |
|
||||
| HTTPS/WSS | ✅ 8361/8363 同证书 TLS1.3、SAN=IP 可达;WSS 桥真实承载信令与媒体建立(客户端全程经 8363 接入) | 窗口日志、preflight |
|
||||
| 嵌入 0 / 语义 stub | ✅ `semantic_backend=stub`,全程零嵌入调用 | `/api/health` |
|
||||
| 字幕 v2 全生命周期 | ✅ seq 单调(三次通话均验证)、interim→final→turn_end / 打断→turn_cancel 无 final | 各 `subtitles.jsonl` |
|
||||
|
||||
## 4. 用量账(逐笔可查,硬闸全程在位)
|
||||
|
||||
- **LLM**:14/40 次请求、42,717/500,000 tokens(`budget_total`/`request_usage`/
|
||||
`token_usage` 逐行;含失败/取消轮,预占语义如代码注释)。结束即封账:
|
||||
`seal_budget_hel879.py` 已执行,封账标记随库归档,真实用量保留不清零。
|
||||
- **TTS**:12/200 合成段(`tts.log` POST /tts 计数;本地 GPU、零外部计费)。
|
||||
- **ASR**:仅窗口内 3 次通话使用(本地 CPU FunASR,零外部计费)。
|
||||
- **嵌入/新增付费**:0。
|
||||
- **语音会话**:建房 6 次 = **3 次真实通话**(含全部验证轮次)+ 3 次工具端
|
||||
崩溃遗留的空会话(1 次手工 DELETE、2 次由 TTL 补偿自动删除;空会话无对话、
|
||||
零模型消耗,如实计数不隐瞒)。
|
||||
|
||||
## 5. 未测 / 留待下轮(如实)
|
||||
|
||||
- **精确 1 秒级打断停声计时**:本轮三次真实打断均已发生并留痕,但帧级停声
|
||||
时间戳未随证据落盘(下一轮客户端应在每帧记录到达时间并按 speech 归属切分)。
|
||||
`call1.json` 已有发布音频到取消3.26秒、到最后agent帧5.3秒、cancel后204帧的
|
||||
原始粗计时,不能隐去这些慢值。该计时未区分触发录音的语音起点、旧speech与
|
||||
后续speech,不能据此量出旧声准确停止时间,**更不能判定达到约1秒**;下轮须
|
||||
定向测量后再作结论。
|
||||
- **「文字打断语音」方向**:本轮竞态取证到反向(语音取消文字);机制同一把锁,
|
||||
下轮把文字触发改为「assistant_interim 出现后」即可定向取证。
|
||||
- **真实设备浏览器路径**(D3 用户动作):证书「高级→继续」两处(8361/8363)、
|
||||
真机麦克风(iOS Safari/安卓 Chrome)未测——须用户设备动作,本轮交付地址与
|
||||
最小步骤,不以 rustls/SSL_CERT_FILE 冒充浏览器例外。
|
||||
- 回复质量观察:长上下文后出现单字回复与一条英文串扰(与测试档案 boundary
|
||||
文案提到「测试/临时」相关)——记录为内容质量观察项,非链路故障。
|
||||
|
||||
## 6. 收尾与回滚
|
||||
|
||||
- 窗口结束:worker/桥/双入口进程全部停止,8360/8361/8363/8082/9880 复核无监听;
|
||||
TTS 按窗口前状态停回(精确 PID 终止,未用 fuser -k,核过无他人占用)。
|
||||
- 受保护服务零接触:8300/8310/8320/8350/7880/7881/10095 原样运行,8340 保持
|
||||
停机,ComfyUI 保持暂停(GPU 回到 97MiB 占用)。
|
||||
- 数据封存:预算封账 + `release_snapshot_hel896.py` 停服一致性快照
|
||||
(`/opt/cybergril-hel879/archives/hel879-r5-window-close-*`,rows_match 全过);
|
||||
证据包 `/opt/cybergril-hel879/hel879-r5-evidence-20261027.tar.gz`
|
||||
(sha256 `b23af43b…c394`,含三次通话字幕/JSON/音频/worker/TTS 日志/清理账)。
|
||||
- 回滚:全部为本轮新建独立进程/目录,删除 `/opt/cybergril-hel879`、
|
||||
`/opt/voice-agent-cybergril`、`/opt/cybergril-voice-certs` 即完全退场;Git 侧
|
||||
为本分支正常追加提交,PR#11 与既有实例未动。
|
||||
|
||||
## 7. 总管独立收尾复核补充
|
||||
|
||||
只读核对14次请求/42717 tokens及sealed=1,封账值与真实用量相等;清理账sessions=0、
|
||||
debts=0,8360/8361/8363/8082/9880无监听。没有重新打开原账或恢复本轮服务。
|
||||
证据包完整SHA256为`b23af43b39ed77263c7b3f285796e77e8b1278acbf547b4619adad600ed5c394`。
|
||||
|
||||
一致性快照已由总管在本地隔离目录按原工具实际恢复,SHA256与三方行数相等,
|
||||
恢复库同为sealed=1、14/42717用量和8条已确认回执。归档永不因上述“回滚”说明
|
||||
自动删除;保留测试资料与证据,销毁须另有明确授权。
|
||||
|
||||
原MANIFEST的code_commit记录8dc84f8(运行时修复尚未提交),不是最终修复提交。
|
||||
独立复核部署中的livekit_wire.py SHA256为
|
||||
`ffc477cd96d48c510905ce9fb887ba5b00edd6941ee59cf1b960f51f18500941`,
|
||||
与3766531收录源码逐字节一致;本说明补足溯源,不篡改原归档。
|
||||
|
||||
本轮只完成R5部分验证,不能称全部R5验收通过。实际6次建房必须连同3个空会话如实
|
||||
保留,不把“3次实际通话”写成“只建房3次”。窗口已收尾且3次实际通话用完,未用
|
||||
模型/token/TTS额度不自动授权新窗口;后续将精确打断计时、文字打断语音和用户设备
|
||||
浏览器路径作为必补项,与自定义音色交回后的统一验证安排集中处理,不擅自重开账。
|
||||
@@ -0,0 +1,96 @@
|
||||
{
|
||||
"rounds": [
|
||||
{
|
||||
"play_label": "xiaoyun",
|
||||
"reply": {
|
||||
"kind": "turn_cancel",
|
||||
"speech_id": "speech_b687b8055307",
|
||||
"reason": "interrupted"
|
||||
}
|
||||
},
|
||||
{
|
||||
"play_label": "bailu",
|
||||
"reply": {
|
||||
"kind": "turn_cancel",
|
||||
"speech_id": "speech_8f12c4a50957",
|
||||
"reason": "no-receipt"
|
||||
}
|
||||
},
|
||||
{
|
||||
"play_label": "jiaojiao",
|
||||
"reply": {
|
||||
"kind": "turn_cancel",
|
||||
"speech_id": "speech_4c73b7d1829c",
|
||||
"reason": "interrupted"
|
||||
}
|
||||
}
|
||||
],
|
||||
"interrupt": {
|
||||
"outcome": "interrupted",
|
||||
"trigger": "audio",
|
||||
"publish_ms": 1793115246711,
|
||||
"cancel_ms": 1793115249971,
|
||||
"cancel_latency_s": 3.26,
|
||||
"last_agent_frame_ms": 1793115252008,
|
||||
"audio_stop_latency_s": 5.3,
|
||||
"frames_after_cancel": 204
|
||||
},
|
||||
"hangup": {
|
||||
"delete_status": 200,
|
||||
"delete_body": {
|
||||
"ended": true,
|
||||
"room": "cg-voice-qeghdnxehn"
|
||||
},
|
||||
"delete_ms": 1793115252011,
|
||||
"agent_frames_after_delete": 2,
|
||||
"room_removed": true
|
||||
},
|
||||
"call": {
|
||||
"tag": "call1",
|
||||
"session": {
|
||||
"url": "wss://192.168.200.12:8363",
|
||||
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6eyJyb29tSm9pbiI6dHJ1ZSwicm9vbSI6ImNnLXZvaWNlLXFlZ2hkbnhlaG4iLCJjYW5QdWJsaXNoIjp0cnVlLCJjYW5TdWJzY3JpYmUiOnRydWUsImNhblB1Ymxpc2hEYXRhIjp0cnVlfSwic3ViIjoidXNlci1nd2h2ZXpjeiIsImlzcyI6ImRldmtleSIsIm5iZiI6MTc5MzExNTIwMywiZXhwIjoxNzkzMTE1NTAzLCJuYW1lIjoi55So5oi3In0.D91S6SXWBtoVoSC6TEsULuK8WNHQu36O_vZQS1urwbw",
|
||||
"room": "cg-voice-qeghdnxehn",
|
||||
"session_id": "Ey8pBEFHbrO8i6Lbc0-47mh7",
|
||||
"agent_name": "cybergril-voice-agent",
|
||||
"epoch": 3,
|
||||
"expires_at": 1793116103636
|
||||
},
|
||||
"subtitle_count": 96,
|
||||
"seq_monotonic": true,
|
||||
"agent_frames": 4766,
|
||||
"agent_audio_seconds": 47.7,
|
||||
"agent_audio_rate": 48000,
|
||||
"agent_joined_ms": 1793115204287,
|
||||
"agent_left_ms": null,
|
||||
"subtitles_file": "/opt/cybergril-hel879/evidence/call1.subtitles.jsonl",
|
||||
"agent_audio_file": "/opt/cybergril-hel879/evidence/call1.agent.wav"
|
||||
},
|
||||
"budget_after": {
|
||||
"at_ms": 1793115254555,
|
||||
"token_usage": [
|
||||
{
|
||||
"day": "2026-10-27",
|
||||
"scene": "dialogue_main",
|
||||
"used": 11416
|
||||
}
|
||||
],
|
||||
"request_usage": [
|
||||
{
|
||||
"day": "2026-10-27",
|
||||
"category": "dialogue",
|
||||
"requests": 4
|
||||
}
|
||||
],
|
||||
"budget_total": [
|
||||
{
|
||||
"key": "total_requests",
|
||||
"value": 4
|
||||
},
|
||||
{
|
||||
"key": "total_tokens",
|
||||
"value": 11416
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
{"v": 2, "seq": 1, "kind": "interim", "role": "user", "text": "盯", "_at_ms": 1793115205011}
|
||||
{"v": 2, "seq": 2, "kind": "interim", "role": "user", "text": "着你看怎", "_at_ms": 1793115205596}
|
||||
{"v": 2, "seq": 3, "kind": "interim", "role": "user", "text": "么啦", "_at_ms": 1793115206196}
|
||||
{"v": 2, "seq": 4, "kind": "user_final", "role": "user", "text": "盯着你看怎么啦", "_at_ms": 1793115207385}
|
||||
{"v": 2, "seq": 5, "kind": "turn_start", "role": "assistant", "text": "", "speech_id": "speech_b687b8055307", "_at_ms": 1793115207410}
|
||||
{"v": 2, "seq": 6, "kind": "interim", "role": "user", "text": "难得", "_at_ms": 1793115207554}
|
||||
{"v": 2, "seq": 7, "kind": "interim", "role": "user", "text": "看你这么", "_at_ms": 1793115208153}
|
||||
{"v": 2, "seq": 8, "kind": "interim", "role": "user", "text": "有意思的", "_at_ms": 1793115208743}
|
||||
{"v": 2, "seq": 9, "kind": "interim", "role": "user", "text": "样子", "_at_ms": 1793115209349}
|
||||
{"v": 2, "seq": 10, "kind": "assistant_interim", "role": "assistant", "text": "没", "speech_id": "speech_b687b8055307", "_at_ms": 1793115209395}
|
||||
{"v": 2, "seq": 11, "kind": "assistant_interim", "role": "assistant", "text": "没怎么", "speech_id": "speech_b687b8055307", "_at_ms": 1793115209436}
|
||||
{"v": 2, "seq": 12, "kind": "assistant_interim", "role": "assistant", "text": "没怎么啦", "speech_id": "speech_b687b8055307", "_at_ms": 1793115209439}
|
||||
{"v": 2, "seq": 13, "kind": "assistant_interim", "role": "assistant", "text": "没怎么啦,", "speech_id": "speech_b687b8055307", "_at_ms": 1793115209478}
|
||||
{"v": 2, "seq": 14, "kind": "assistant_interim", "role": "assistant", "text": "没怎么啦,工程师", "speech_id": "speech_b687b8055307", "_at_ms": 1793115209479}
|
||||
{"v": 2, "seq": 15, "kind": "assistant_interim", "role": "assistant", "text": "没怎么啦,工程师。", "speech_id": "speech_b687b8055307", "_at_ms": 1793115209522}
|
||||
{"v": 2, "seq": 16, "kind": "assistant_interim", "role": "assistant", "text": "没怎么啦,工程师。你", "speech_id": "speech_b687b8055307", "_at_ms": 1793115209563}
|
||||
{"v": 2, "seq": 17, "kind": "assistant_interim", "role": "assistant", "text": "没怎么啦,工程师。你盯着", "speech_id": "speech_b687b8055307", "_at_ms": 1793115209565}
|
||||
{"v": 2, "seq": 18, "kind": "assistant_interim", "role": "assistant", "text": "没怎么啦,工程师。你盯着看", "speech_id": "speech_b687b8055307", "_at_ms": 1793115209605}
|
||||
{"v": 2, "seq": 19, "kind": "assistant_interim", "role": "assistant", "text": "没怎么啦,工程师。你盯着看,", "speech_id": "speech_b687b8055307", "_at_ms": 1793115209611}
|
||||
{"v": 2, "seq": 20, "kind": "assistant_interim", "role": "assistant", "text": "没怎么啦,工程师。你盯着看,我就", "speech_id": "speech_b687b8055307", "_at_ms": 1793115209650}
|
||||
{"v": 2, "seq": 21, "kind": "assistant_interim", "role": "assistant", "text": "没怎么啦,工程师。你盯着看,我就当", "speech_id": "speech_b687b8055307", "_at_ms": 1793115209688}
|
||||
{"v": 2, "seq": 22, "kind": "assistant_interim", "role": "assistant", "text": "没怎么啦,工程师。你盯着看,我就当你在", "speech_id": "speech_b687b8055307", "_at_ms": 1793115209731}
|
||||
{"v": 2, "seq": 23, "kind": "assistant_interim", "role": "assistant", "text": "没怎么啦,工程师。你盯着看,我就当你在检查", "speech_id": "speech_b687b8055307", "_at_ms": 1793115209773}
|
||||
{"v": 2, "seq": 24, "kind": "assistant_interim", "role": "assistant", "text": "没怎么啦,工程师。你盯着看,我就当你在检查我", "speech_id": "speech_b687b8055307", "_at_ms": 1793115209816}
|
||||
{"v": 2, "seq": 25, "kind": "assistant_interim", "role": "assistant", "text": "没怎么啦,工程师。你盯着看,我就当你在检查我有没有", "speech_id": "speech_b687b8055307", "_at_ms": 1793115209816}
|
||||
{"v": 2, "seq": 26, "kind": "assistant_interim", "role": "assistant", "text": "没怎么啦,工程师。你盯着看,我就当你在检查我有没有乱", "speech_id": "speech_b687b8055307", "_at_ms": 1793115209857}
|
||||
{"v": 2, "seq": 27, "kind": "assistant_interim", "role": "assistant", "text": "没怎么啦,工程师。你盯着看,我就当你在检查我有没有乱动", "speech_id": "speech_b687b8055307", "_at_ms": 1793115209900}
|
||||
{"v": 2, "seq": 28, "kind": "assistant_interim", "role": "assistant", "text": "没怎么啦,工程师。你盯着看,我就当你在检查我有没有乱动。", "speech_id": "speech_b687b8055307", "_at_ms": 1793115209947}
|
||||
{"v": 2, "seq": 29, "kind": "user_final", "role": "user", "text": "难得看你这么有意思的样子吗", "_at_ms": 1793115210503}
|
||||
{"v": 2, "seq": 30, "kind": "turn_cancel", "role": "assistant", "text": "", "speech_id": "speech_b687b8055307", "reason": "interrupted", "_at_ms": 1793115210511}
|
||||
{"v": 2, "seq": 31, "kind": "interim", "role": "user", "text": "烈会军校", "_at_ms": 1793115212136}
|
||||
{"v": 2, "seq": 32, "kind": "interim", "role": "user", "text": "校啊招", "_at_ms": 1793115212733}
|
||||
{"v": 2, "seq": 33, "kind": "interim", "role": "user", "text": "啊这种类", "_at_ms": 1793115213338}
|
||||
{"v": 2, "seq": 34, "kind": "interim", "role": "user", "text": "型我都是", "_at_ms": 1793115213936}
|
||||
{"v": 2, "seq": 35, "kind": "interim", "role": "user", "text": "那种比较", "_at_ms": 1793115214541}
|
||||
{"v": 2, "seq": 36, "kind": "interim", "role": "user", "text": "呃豪", "_at_ms": 1793115215744}
|
||||
{"v": 2, "seq": 37, "kind": "interim", "role": "user", "text": "爽比", "_at_ms": 1793115216340}
|
||||
{"v": 2, "seq": 38, "kind": "interim", "role": "user", "text": "较开", "_at_ms": 1793115216943}
|
||||
{"v": 2, "seq": 39, "kind": "interim", "role": "user", "text": "朗的那种", "_at_ms": 1793115217541}
|
||||
{"v": 2, "seq": 40, "kind": "interim", "role": "user", "text": "类型", "_at_ms": 1793115218142}
|
||||
{"v": 2, "seq": 41, "kind": "interim", "role": "user", "text": "阳光大", "_at_ms": 1793115218753}
|
||||
{"v": 2, "seq": 42, "kind": "interim", "role": "user", "text": "女孩", "_at_ms": 1793115219344}
|
||||
{"v": 2, "seq": 43, "kind": "interim", "role": "user", "text": "那种感", "_at_ms": 1793115220543}
|
||||
{"v": 2, "seq": 44, "kind": "interim", "role": "user", "text": "觉", "_at_ms": 1793115221139}
|
||||
{"v": 2, "seq": 45, "kind": "interim", "role": "user", "text": "都给", "_at_ms": 1793115221743}
|
||||
{"v": 2, "seq": 46, "kind": "user_final", "role": "user", "text": "烈火军校啊,朝阳啊这种类型我都是那种比较呃豪爽,比较开朗的那种类型,阳光大女孩那种感觉就", "_at_ms": 1793115223193}
|
||||
{"v": 2, "seq": 47, "kind": "turn_start", "role": "assistant", "text": "", "speech_id": "speech_8f12c4a50957", "_at_ms": 1793115226967}
|
||||
{"v": 2, "seq": 48, "kind": "assistant_interim", "role": "assistant", "text": "原来", "speech_id": "speech_8f12c4a50957", "_at_ms": 1793115228249}
|
||||
{"v": 2, "seq": 49, "kind": "assistant_interim", "role": "assistant", "text": "原来你是", "speech_id": "speech_8f12c4a50957", "_at_ms": 1793115228291}
|
||||
{"v": 2, "seq": 50, "kind": "assistant_interim", "role": "assistant", "text": "原来你是那种", "speech_id": "speech_8f12c4a50957", "_at_ms": 1793115228333}
|
||||
{"v": 2, "seq": 51, "kind": "assistant_interim", "role": "assistant", "text": "原来你是那种阳光", "speech_id": "speech_8f12c4a50957", "_at_ms": 1793115228335}
|
||||
{"v": 2, "seq": 52, "kind": "assistant_interim", "role": "assistant", "text": "原来你是那种阳光大", "speech_id": "speech_8f12c4a50957", "_at_ms": 1793115228376}
|
||||
{"v": 2, "seq": 53, "kind": "assistant_interim", "role": "assistant", "text": "原来你是那种阳光大女孩", "speech_id": "speech_8f12c4a50957", "_at_ms": 1793115228377}
|
||||
{"v": 2, "seq": 54, "kind": "assistant_interim", "role": "assistant", "text": "原来你是那种阳光大女孩的类型", "speech_id": "speech_8f12c4a50957", "_at_ms": 1793115228420}
|
||||
{"v": 2, "seq": 55, "kind": "assistant_interim", "role": "assistant", "text": "原来你是那种阳光大女孩的类型啊", "speech_id": "speech_8f12c4a50957", "_at_ms": 1793115228464}
|
||||
{"v": 2, "seq": 56, "kind": "assistant_interim", "role": "assistant", "text": "原来你是那种阳光大女孩的类型啊,", "speech_id": "speech_8f12c4a50957", "_at_ms": 1793115228506}
|
||||
{"v": 2, "seq": 57, "kind": "assistant_interim", "role": "assistant", "text": "原来你是那种阳光大女孩的类型啊,难怪", "speech_id": "speech_8f12c4a50957", "_at_ms": 1793115228508}
|
||||
{"v": 2, "seq": 58, "kind": "assistant_interim", "role": "assistant", "text": "原来你是那种阳光大女孩的类型啊,难怪感觉", "speech_id": "speech_8f12c4a50957", "_at_ms": 1793115228548}
|
||||
{"v": 2, "seq": 59, "kind": "assistant_interim", "role": "assistant", "text": "原来你是那种阳光大女孩的类型啊,难怪感觉你", "speech_id": "speech_8f12c4a50957", "_at_ms": 1793115228590}
|
||||
{"v": 2, "seq": 60, "kind": "assistant_interim", "role": "assistant", "text": "原来你是那种阳光大女孩的类型啊,难怪感觉你说话", "speech_id": "speech_8f12c4a50957", "_at_ms": 1793115228634}
|
||||
{"v": 2, "seq": 61, "kind": "assistant_interim", "role": "assistant", "text": "原来你是那种阳光大女孩的类型啊,难怪感觉你说话都", "speech_id": "speech_8f12c4a50957", "_at_ms": 1793115228636}
|
||||
{"v": 2, "seq": 62, "kind": "assistant_interim", "role": "assistant", "text": "原来你是那种阳光大女孩的类型啊,难怪感觉你说话都透", "speech_id": "speech_8f12c4a50957", "_at_ms": 1793115228674}
|
||||
{"v": 2, "seq": 63, "kind": "assistant_interim", "role": "assistant", "text": "原来你是那种阳光大女孩的类型啊,难怪感觉你说话都透着一股", "speech_id": "speech_8f12c4a50957", "_at_ms": 1793115228716}
|
||||
{"v": 2, "seq": 64, "kind": "assistant_interim", "role": "assistant", "text": "原来你是那种阳光大女孩的类型啊,难怪感觉你说话都透着一股豪", "speech_id": "speech_8f12c4a50957", "_at_ms": 1793115228717}
|
||||
{"v": 2, "seq": 65, "kind": "assistant_interim", "role": "assistant", "text": "原来你是那种阳光大女孩的类型啊,难怪感觉你说话都透着一股豪爽", "speech_id": "speech_8f12c4a50957", "_at_ms": 1793115228758}
|
||||
{"v": 2, "seq": 66, "kind": "assistant_interim", "role": "assistant", "text": "原来你是那种阳光大女孩的类型啊,难怪感觉你说话都透着一股豪爽劲儿", "speech_id": "speech_8f12c4a50957", "_at_ms": 1793115228760}
|
||||
{"v": 2, "seq": 67, "kind": "assistant_interim", "role": "assistant", "text": "原来你是那种阳光大女孩的类型啊,难怪感觉你说话都透着一股豪爽劲儿。", "speech_id": "speech_8f12c4a50957", "_at_ms": 1793115228801}
|
||||
{"v": 2, "seq": 68, "kind": "turn_cancel", "role": "assistant", "text": "", "speech_id": "speech_8f12c4a50957", "reason": "no-receipt", "_at_ms": 1793115239147}
|
||||
{"v": 2, "seq": 69, "kind": "interim", "role": "user", "text": "怎么还", "_at_ms": 1793115240503}
|
||||
{"v": 2, "seq": 70, "kind": "interim", "role": "user", "text": "有没事", "_at_ms": 1793115241090}
|
||||
{"v": 2, "seq": 71, "kind": "interim", "role": "user", "text": "的", "_at_ms": 1793115241700}
|
||||
{"v": 2, "seq": 72, "kind": "user_final", "role": "user", "text": "怎么还有没事的", "_at_ms": 1793115242576}
|
||||
{"v": 2, "seq": 73, "kind": "turn_start", "role": "assistant", "text": "", "speech_id": "speech_4c73b7d1829c", "_at_ms": 1793115242585}
|
||||
{"v": 2, "seq": 74, "kind": "interim", "role": "user", "text": "是我不够", "_at_ms": 1793115243790}
|
||||
{"v": 2, "seq": 75, "kind": "assistant_interim", "role": "assistant", "text": "哈哈", "speech_id": "speech_4c73b7d1829c", "_at_ms": 1793115243833}
|
||||
{"v": 2, "seq": 76, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,", "speech_id": "speech_4c73b7d1829c", "_at_ms": 1793115243874}
|
||||
{"v": 2, "seq": 77, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,因为", "speech_id": "speech_4c73b7d1829c", "_at_ms": 1793115243875}
|
||||
{"v": 2, "seq": 78, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,因为我在", "speech_id": "speech_4c73b7d1829c", "_at_ms": 1793115243916}
|
||||
{"v": 2, "seq": 79, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,因为我在认真", "speech_id": "speech_4c73b7d1829c", "_at_ms": 1793115243917}
|
||||
{"v": 2, "seq": 80, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,因为我在认真听", "speech_id": "speech_4c73b7d1829c", "_at_ms": 1793115243958}
|
||||
{"v": 2, "seq": 81, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,因为我在认真听你", "speech_id": "speech_4c73b7d1829c", "_at_ms": 1793115244002}
|
||||
{"v": 2, "seq": 82, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,因为我在认真听你说话", "speech_id": "speech_4c73b7d1829c", "_at_ms": 1793115244044}
|
||||
{"v": 2, "seq": 83, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,因为我在认真听你说话呀", "speech_id": "speech_4c73b7d1829c", "_at_ms": 1793115244045}
|
||||
{"v": 2, "seq": 84, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,因为我在认真听你说话呀。", "speech_id": "speech_4c73b7d1829c", "_at_ms": 1793115244086}
|
||||
{"v": 2, "seq": 85, "kind": "interim", "role": "user", "text": "努力", "_at_ms": 1793115244386}
|
||||
{"v": 2, "seq": 86, "kind": "user_final", "role": "user", "text": "是我不够努力吗", "_at_ms": 1793115245511}
|
||||
{"v": 2, "seq": 87, "kind": "turn_cancel", "role": "assistant", "text": "", "speech_id": "speech_4c73b7d1829c", "reason": "interrupted", "_at_ms": 1793115245516}
|
||||
{"v": 2, "seq": 88, "kind": "interim", "role": "user", "text": "盯着你看", "_at_ms": 1793115248139}
|
||||
{"v": 2, "seq": 89, "kind": "interim", "role": "user", "text": "怎么", "_at_ms": 1793115248742}
|
||||
{"v": 2, "seq": 90, "kind": "turn_start", "role": "assistant", "text": "", "speech_id": "speech_7a9c0f804ca0", "_at_ms": 1793115249065}
|
||||
{"v": 2, "seq": 91, "kind": "user_final", "role": "user", "text": "盯着你看怎么啦", "_at_ms": 1793115249963}
|
||||
{"v": 2, "seq": 92, "kind": "turn_cancel", "role": "assistant", "text": "", "speech_id": "speech_7a9c0f804ca0", "reason": "interrupted", "_at_ms": 1793115249971}
|
||||
{"v": 2, "seq": 93, "kind": "interim", "role": "user", "text": "难得", "_at_ms": 1793115250198}
|
||||
{"v": 2, "seq": 94, "kind": "interim", "role": "user", "text": "看你这么", "_at_ms": 1793115250808}
|
||||
{"v": 2, "seq": 95, "kind": "interim", "role": "user", "text": "有意思的", "_at_ms": 1793115251389}
|
||||
{"v": 2, "seq": 96, "kind": "interim", "role": "user", "text": "样子", "_at_ms": 1793115251989}
|
||||
@@ -0,0 +1,97 @@
|
||||
{
|
||||
"rounds": [
|
||||
{
|
||||
"play_label": "haimianbaobao",
|
||||
"reply": {
|
||||
"kind": "turn_end",
|
||||
"speech_id": "speech_e69e351f1c44",
|
||||
"reason": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"play_label": "nezha",
|
||||
"reply": {
|
||||
"kind": "turn_end",
|
||||
"speech_id": "speech_ff61928cdce0",
|
||||
"reason": null
|
||||
}
|
||||
},
|
||||
{
|
||||
"play_label": "rain",
|
||||
"reply": {
|
||||
"kind": "turn_end",
|
||||
"speech_id": "speech_2f9dc8b9848d",
|
||||
"reason": null
|
||||
}
|
||||
}
|
||||
],
|
||||
"interrupt": {
|
||||
"outcome": "no-cancel",
|
||||
"trigger": "audio",
|
||||
"publish_ms": 1793115490292,
|
||||
"cancel_ms": null,
|
||||
"cancel_latency_s": null,
|
||||
"old_audio_stop_ms": 1793115512315,
|
||||
"old_audio_stop_latency_s": 22.02,
|
||||
"old_frames_during_interrupt": 2203,
|
||||
"frames_after_cancel_plus1s5": 0
|
||||
},
|
||||
"hangup": {
|
||||
"delete_status": 200,
|
||||
"delete_body": {
|
||||
"ended": true,
|
||||
"room": "cg-voice-5c4y64wxkl"
|
||||
},
|
||||
"delete_ms": 1793115512327,
|
||||
"agent_frames_after_delete": 2,
|
||||
"room_removed": true
|
||||
},
|
||||
"call": {
|
||||
"tag": "call1",
|
||||
"session": {
|
||||
"url": "wss://192.168.200.12:8363",
|
||||
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6eyJyb29tSm9pbiI6dHJ1ZSwicm9vbSI6ImNnLXZvaWNlLTVjNHk2NHd4a2wiLCJjYW5QdWJsaXNoIjp0cnVlLCJjYW5TdWJzY3JpYmUiOnRydWUsImNhblB1Ymxpc2hEYXRhIjp0cnVlfSwic3ViIjoidXNlci12ZHl3c2h2ZSIsImlzcyI6ImRldmtleSIsIm5iZiI6MTc5MzExNTQzMSwiZXhwIjoxNzkzMTE1NzMxLCJuYW1lIjoi55So5oi3In0.PjOElCid-0VLPw8w0iQml4ca9QkLqoCwu9EJf2pz4DE",
|
||||
"room": "cg-voice-5c4y64wxkl",
|
||||
"session_id": "jCiBIdbaj2_2_AjxrwChbQ4A",
|
||||
"agent_name": "cybergril-voice-agent",
|
||||
"epoch": 4,
|
||||
"expires_at": 1793116331245
|
||||
},
|
||||
"subtitle_count": 98,
|
||||
"seq_monotonic": true,
|
||||
"agent_frames": 8042,
|
||||
"agent_audio_seconds": 80.4,
|
||||
"agent_audio_rate": 48000,
|
||||
"agent_joined_ms": 1793115431859,
|
||||
"agent_left_ms": null,
|
||||
"subtitles_file": "/opt/cybergril-hel879/evidence/call1b.subtitles.jsonl",
|
||||
"agent_audio_file": "/opt/cybergril-hel879/evidence/call1b.agent.wav"
|
||||
},
|
||||
"budget_after": {
|
||||
"at_ms": 1793115514868,
|
||||
"token_usage": [
|
||||
{
|
||||
"day": "2026-10-27",
|
||||
"scene": "dialogue_main",
|
||||
"used": 23504
|
||||
}
|
||||
],
|
||||
"request_usage": [
|
||||
{
|
||||
"day": "2026-10-27",
|
||||
"category": "dialogue",
|
||||
"requests": 8
|
||||
}
|
||||
],
|
||||
"budget_total": [
|
||||
{
|
||||
"key": "total_requests",
|
||||
"value": 8
|
||||
},
|
||||
{
|
||||
"key": "total_tokens",
|
||||
"value": 23504
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
{"v": 2, "seq": 1, "kind": "interim", "role": "user", "text": "没", "_at_ms": 1793115432559}
|
||||
{"v": 2, "seq": 2, "kind": "interim", "role": "user", "text": "错", "_at_ms": 1793115433170}
|
||||
{"v": 2, "seq": 3, "kind": "interim", "role": "user", "text": "我就是个", "_at_ms": 1793115433760}
|
||||
{"v": 2, "seq": 4, "kind": "interim", "role": "user", "text": "笨蛋", "_at_ms": 1793115434360}
|
||||
{"v": 2, "seq": 5, "kind": "interim", "role": "user", "text": "派大星", "_at_ms": 1793115434960}
|
||||
{"v": 2, "seq": 6, "kind": "interim", "role": "user", "text": "我们", "_at_ms": 1793115435559}
|
||||
{"v": 2, "seq": 7, "kind": "interim", "role": "user", "text": "一起去", "_at_ms": 1793115436165}
|
||||
{"v": 2, "seq": 8, "kind": "interim", "role": "user", "text": "抓水母", "_at_ms": 1793115436768}
|
||||
{"v": 2, "seq": 9, "kind": "interim", "role": "user", "text": "吧我", "_at_ms": 1793115437365}
|
||||
{"v": 2, "seq": 10, "kind": "interim", "role": "user", "text": "们一起度", "_at_ms": 1793115437963}
|
||||
{"v": 2, "seq": 11, "kind": "interim", "role": "user", "text": "过快乐的", "_at_ms": 1793115438565}
|
||||
{"v": 2, "seq": 12, "kind": "interim", "role": "user", "text": "一天", "_at_ms": 1793115439163}
|
||||
{"v": 2, "seq": 13, "kind": "user_final", "role": "user", "text": "没错,我就是个笨蛋派大星,我们一起去抓水母吧,我们一起度过快乐的一天", "_at_ms": 1793115440793}
|
||||
{"v": 2, "seq": 14, "kind": "turn_start", "role": "assistant", "text": "", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115440831}
|
||||
{"v": 2, "seq": 15, "kind": "assistant_interim", "role": "assistant", "text": "好", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115442938}
|
||||
{"v": 2, "seq": 16, "kind": "assistant_interim", "role": "assistant", "text": "好呀", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115442940}
|
||||
{"v": 2, "seq": 17, "kind": "assistant_interim", "role": "assistant", "text": "好呀,", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115442981}
|
||||
{"v": 2, "seq": 18, "kind": "assistant_interim", "role": "assistant", "text": "好呀,那我们", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115442984}
|
||||
{"v": 2, "seq": 19, "kind": "assistant_interim", "role": "assistant", "text": "好呀,那我们这就", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115443024}
|
||||
{"v": 2, "seq": 20, "kind": "assistant_interim", "role": "assistant", "text": "好呀,那我们这就出发", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115443067}
|
||||
{"v": 2, "seq": 21, "kind": "assistant_interim", "role": "assistant", "text": "好呀,那我们这就出发去", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115443068}
|
||||
{"v": 2, "seq": 22, "kind": "assistant_interim", "role": "assistant", "text": "好呀,那我们这就出发去抓", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115443109}
|
||||
{"v": 2, "seq": 23, "kind": "assistant_interim", "role": "assistant", "text": "好呀,那我们这就出发去抓水", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115443110}
|
||||
{"v": 2, "seq": 24, "kind": "assistant_interim", "role": "assistant", "text": "好呀,那我们这就出发去抓水母", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115443152}
|
||||
{"v": 2, "seq": 25, "kind": "assistant_interim", "role": "assistant", "text": "好呀,那我们这就出发去抓水母!", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115443154}
|
||||
{"v": 2, "seq": 26, "kind": "assistant_interim", "role": "assistant", "text": "好呀,那我们这就出发去抓水母!不过", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115443195}
|
||||
{"v": 2, "seq": 27, "kind": "assistant_interim", "role": "assistant", "text": "好呀,那我们这就出发去抓水母!不过我可", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115443237}
|
||||
{"v": 2, "seq": 28, "kind": "assistant_interim", "role": "assistant", "text": "好呀,那我们这就出发去抓水母!不过我可不想", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115443238}
|
||||
{"v": 2, "seq": 29, "kind": "assistant_interim", "role": "assistant", "text": "好呀,那我们这就出发去抓水母!不过我可不想住", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115443279}
|
||||
{"v": 2, "seq": 30, "kind": "assistant_interim", "role": "assistant", "text": "好呀,那我们这就出发去抓水母!不过我可不想住进", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115443321}
|
||||
{"v": 2, "seq": 31, "kind": "assistant_interim", "role": "assistant", "text": "好呀,那我们这就出发去抓水母!不过我可不想住进那个", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115443322}
|
||||
{"v": 2, "seq": 32, "kind": "assistant_interim", "role": "assistant", "text": "好呀,那我们这就出发去抓水母!不过我可不想住进那个菠萝", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115443363}
|
||||
{"v": 2, "seq": 33, "kind": "assistant_interim", "role": "assistant", "text": "好呀,那我们这就出发去抓水母!不过我可不想住进那个菠萝屋", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115443406}
|
||||
{"v": 2, "seq": 34, "kind": "assistant_interim", "role": "assistant", "text": "好呀,那我们这就出发去抓水母!不过我可不想住进那个菠萝屋,", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115443449}
|
||||
{"v": 2, "seq": 35, "kind": "assistant_interim", "role": "assistant", "text": "好呀,那我们这就出发去抓水母!不过我可不想住进那个菠萝屋,我只", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115443450}
|
||||
{"v": 2, "seq": 36, "kind": "assistant_interim", "role": "assistant", "text": "好呀,那我们这就出发去抓水母!不过我可不想住进那个菠萝屋,我只喜欢", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115443491}
|
||||
{"v": 2, "seq": 37, "kind": "assistant_interim", "role": "assistant", "text": "好呀,那我们这就出发去抓水母!不过我可不想住进那个菠萝屋,我只喜欢在海", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115443534}
|
||||
{"v": 2, "seq": 38, "kind": "assistant_interim", "role": "assistant", "text": "好呀,那我们这就出发去抓水母!不过我可不想住进那个菠萝屋,我只喜欢在海边", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115443577}
|
||||
{"v": 2, "seq": 39, "kind": "assistant_interim", "role": "assistant", "text": "好呀,那我们这就出发去抓水母!不过我可不想住进那个菠萝屋,我只喜欢在海边晒太阳", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115443578}
|
||||
{"v": 2, "seq": 40, "kind": "assistant_interim", "role": "assistant", "text": "好呀,那我们这就出发去抓水母!不过我可不想住进那个菠萝屋,我只喜欢在海边晒太阳。", "speech_id": "speech_e69e351f1c44", "_at_ms": 1793115443620}
|
||||
{"v": 2, "seq": 41, "kind": "assistant_final", "role": "assistant", "text": "好呀,那我们这就出发去抓水母!不过我可不想住进那个菠萝屋,我只喜欢在海边晒太阳。", "speech_id": "speech_e69e351f1c44", "turn_id": "b72de17e-bf42-470e-b396-c219bd7593f9", "_at_ms": 1793115457080}
|
||||
{"v": 2, "seq": 42, "kind": "turn_end", "role": "assistant", "text": "", "speech_id": "speech_e69e351f1c44", "turn_id": "b72de17e-bf42-470e-b396-c219bd7593f9", "_at_ms": 1793115457081}
|
||||
{"v": 2, "seq": 43, "kind": "interim", "role": "user", "text": "天雷滚", "_at_ms": 1793115458260}
|
||||
{"v": 2, "seq": 44, "kind": "interim", "role": "user", "text": "滚我好", "_at_ms": 1793115458865}
|
||||
{"v": 2, "seq": 45, "kind": "interim", "role": "user", "text": "怕怕", "_at_ms": 1793115459463}
|
||||
{"v": 2, "seq": 46, "kind": "interim", "role": "user", "text": "劈", "_at_ms": 1793115460064}
|
||||
{"v": 2, "seq": 47, "kind": "interim", "role": "user", "text": "的我浑", "_at_ms": 1793115460657}
|
||||
{"v": 2, "seq": 48, "kind": "interim", "role": "user", "text": "身掉渣", "_at_ms": 1793115461256}
|
||||
{"v": 2, "seq": 49, "kind": "interim", "role": "user", "text": "渣突", "_at_ms": 1793115461862}
|
||||
{"v": 2, "seq": 50, "kind": "interim", "role": "user", "text": "破天", "_at_ms": 1793115462458}
|
||||
{"v": 2, "seq": 51, "kind": "interim", "role": "user", "text": "劫我笑", "_at_ms": 1793115463067}
|
||||
{"v": 2, "seq": 52, "kind": "interim", "role": "user", "text": "哈哈", "_at_ms": 1793115463659}
|
||||
{"v": 2, "seq": 53, "kind": "interim", "role": "user", "text": "逆", "_at_ms": 1793115464263}
|
||||
{"v": 2, "seq": 54, "kind": "interim", "role": "user", "text": "天改命", "_at_ms": 1793115464867}
|
||||
{"v": 2, "seq": 55, "kind": "interim", "role": "user", "text": "我吹喇", "_at_ms": 1793115465459}
|
||||
{"v": 2, "seq": 56, "kind": "interim", "role": "user", "text": "叭滴", "_at_ms": 1793115466062}
|
||||
{"v": 2, "seq": 57, "kind": "interim", "role": "user", "text": "答滴答", "_at_ms": 1793115466663}
|
||||
{"v": 2, "seq": 58, "kind": "interim", "role": "user", "text": "滴滴", "_at_ms": 1793115467270}
|
||||
{"v": 2, "seq": 59, "kind": "user_final", "role": "user", "text": "天雷滚滚,我好怕怕劈的我浑身掉渣渣,突破天劫,我笑哈哈逆天改命,我吹喇叭滴答滴答,滴滴答", "_at_ms": 1793115468935}
|
||||
{"v": 2, "seq": 60, "kind": "turn_start", "role": "assistant", "text": "", "speech_id": "speech_ff61928cdce0", "_at_ms": 1793115468946}
|
||||
{"v": 2, "seq": 61, "kind": "assistant_interim", "role": "assistant", "text": "哈哈", "speech_id": "speech_ff61928cdce0", "_at_ms": 1793115470187}
|
||||
{"v": 2, "seq": 62, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,", "speech_id": "speech_ff61928cdce0", "_at_ms": 1793115470230}
|
||||
{"v": 2, "seq": 63, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,你", "speech_id": "speech_ff61928cdce0", "_at_ms": 1793115470231}
|
||||
{"v": 2, "seq": 64, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,你唱", "speech_id": "speech_ff61928cdce0", "_at_ms": 1793115470273}
|
||||
{"v": 2, "seq": 65, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,你唱得", "speech_id": "speech_ff61928cdce0", "_at_ms": 1793115470315}
|
||||
{"v": 2, "seq": 66, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,你唱得还挺", "speech_id": "speech_ff61928cdce0", "_at_ms": 1793115470316}
|
||||
{"v": 2, "seq": 67, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,你唱得还挺有", "speech_id": "speech_ff61928cdce0", "_at_ms": 1793115470357}
|
||||
{"v": 2, "seq": 68, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,你唱得还挺有节奏", "speech_id": "speech_ff61928cdce0", "_at_ms": 1793115470359}
|
||||
{"v": 2, "seq": 69, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,你唱得还挺有节奏感的", "speech_id": "speech_ff61928cdce0", "_at_ms": 1793115470400}
|
||||
{"v": 2, "seq": 70, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,你唱得还挺有节奏感的!", "speech_id": "speech_ff61928cdce0", "_at_ms": 1793115470443}
|
||||
{"v": 2, "seq": 71, "kind": "assistant_final", "role": "assistant", "text": "哈哈,你唱得还挺有节奏感的!", "speech_id": "speech_ff61928cdce0", "turn_id": "baa6c5c7-b483-49d4-905c-d6b7e5dd7786", "_at_ms": 1793115476107}
|
||||
{"v": 2, "seq": 72, "kind": "turn_end", "role": "assistant", "text": "", "speech_id": "speech_ff61928cdce0", "turn_id": "baa6c5c7-b483-49d4-905c-d6b7e5dd7786", "_at_ms": 1793115476109}
|
||||
{"v": 2, "seq": 73, "kind": "interim", "role": "user", "text": "你是不是", "_at_ms": 1793115477463}
|
||||
{"v": 2, "seq": 74, "kind": "interim", "role": "user", "text": "早就想", "_at_ms": 1793115478068}
|
||||
{"v": 2, "seq": 75, "kind": "interim", "role": "user", "text": "睡我", "_at_ms": 1793115478661}
|
||||
{"v": 2, "seq": 76, "kind": "interim", "role": "user", "text": "了", "_at_ms": 1793115479267}
|
||||
{"v": 2, "seq": 77, "kind": "user_final", "role": "user", "text": "你是不是早就想睡我了呀", "_at_ms": 1793115480206}
|
||||
{"v": 2, "seq": 78, "kind": "turn_start", "role": "assistant", "text": "", "speech_id": "speech_2f9dc8b9848d", "_at_ms": 1793115480215}
|
||||
{"v": 2, "seq": 79, "kind": "assistant_interim", "role": "assistant", "text": "哈哈", "speech_id": "speech_2f9dc8b9848d", "_at_ms": 1793115481774}
|
||||
{"v": 2, "seq": 80, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,", "speech_id": "speech_2f9dc8b9848d", "_at_ms": 1793115481776}
|
||||
{"v": 2, "seq": 81, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,你", "speech_id": "speech_2f9dc8b9848d", "_at_ms": 1793115481816}
|
||||
{"v": 2, "seq": 82, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,你思维", "speech_id": "speech_2f9dc8b9848d", "_at_ms": 1793115481816}
|
||||
{"v": 2, "seq": 83, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,你思维跳跃", "speech_id": "speech_2f9dc8b9848d", "_at_ms": 1793115481857}
|
||||
{"v": 2, "seq": 84, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,你思维跳跃得太", "speech_id": "speech_2f9dc8b9848d", "_at_ms": 1793115481859}
|
||||
{"v": 2, "seq": 85, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,你思维跳跃得太快了", "speech_id": "speech_2f9dc8b9848d", "_at_ms": 1793115481903}
|
||||
{"v": 2, "seq": 86, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,你思维跳跃得太快了,", "speech_id": "speech_2f9dc8b9848d", "_at_ms": 1793115481906}
|
||||
{"v": 2, "seq": 87, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,你思维跳跃得太快了,我都", "speech_id": "speech_2f9dc8b9848d", "_at_ms": 1793115481945}
|
||||
{"v": 2, "seq": 88, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,你思维跳跃得太快了,我都跟不上", "speech_id": "speech_2f9dc8b9848d", "_at_ms": 1793115481987}
|
||||
{"v": 2, "seq": 89, "kind": "assistant_interim", "role": "assistant", "text": "哈哈,你思维跳跃得太快了,我都跟不上。", "speech_id": "speech_2f9dc8b9848d", "_at_ms": 1793115481988}
|
||||
{"v": 2, "seq": 90, "kind": "assistant_final", "role": "assistant", "text": "哈哈,你思维跳跃得太快了,我都跟不上。", "speech_id": "speech_2f9dc8b9848d", "turn_id": "a91bbbb6-45b0-4671-84a2-027cc194f420", "_at_ms": 1793115489067}
|
||||
{"v": 2, "seq": 91, "kind": "turn_end", "role": "assistant", "text": "", "speech_id": "speech_2f9dc8b9848d", "turn_id": "a91bbbb6-45b0-4671-84a2-027cc194f420", "_at_ms": 1793115489068}
|
||||
{"v": 2, "seq": 92, "kind": "interim", "role": "user", "text": "盯着你看", "_at_ms": 1793115491717}
|
||||
{"v": 2, "seq": 93, "kind": "interim", "role": "user", "text": "怎么啦", "_at_ms": 1793115492309}
|
||||
{"v": 2, "seq": 94, "kind": "user_final", "role": "user", "text": "盯着你看怎么啦", "_at_ms": 1793115493388}
|
||||
{"v": 2, "seq": 95, "kind": "turn_start", "role": "assistant", "text": "", "speech_id": "speech_0d075d37bc31", "_at_ms": 1793115493398}
|
||||
{"v": 2, "seq": 96, "kind": "assistant_interim", "role": "assistant", "text": "没", "speech_id": "speech_0d075d37bc31", "_at_ms": 1793115494608}
|
||||
{"v": 2, "seq": 97, "kind": "assistant_final", "role": "assistant", "text": "没", "speech_id": "speech_0d075d37bc31", "turn_id": "5bd95c66-b42b-4571-bfc2-fbf376c90747", "_at_ms": 1793115501161}
|
||||
{"v": 2, "seq": 98, "kind": "turn_end", "role": "assistant", "text": "", "speech_id": "speech_0d075d37bc31", "turn_id": "5bd95c66-b42b-4571-bfc2-fbf376c90747", "_at_ms": 1793115501163}
|
||||
@@ -0,0 +1,303 @@
|
||||
{
|
||||
"barges": [
|
||||
{
|
||||
"label": "bajie",
|
||||
"outcome": "reply-too-short-to-barge"
|
||||
},
|
||||
{
|
||||
"label": "sunwukong",
|
||||
"outcome": "reply-too-short-to-barge"
|
||||
},
|
||||
{
|
||||
"label": "haimianbaobao",
|
||||
"outcome": "reply-too-short-to-barge"
|
||||
}
|
||||
],
|
||||
"text_turn": {
|
||||
"turn_id": "cb1bbe27-795f-45e3-b7bf-f2d6371c0830",
|
||||
"status": 200,
|
||||
"deltas": 0,
|
||||
"final": null,
|
||||
"ms": 114
|
||||
},
|
||||
"voice_reply_after_text": {
|
||||
"kind": "turn_end",
|
||||
"speech_id": "speech_9aa32dc387c3",
|
||||
"reason": null
|
||||
},
|
||||
"voice_cancelled_by_text": false,
|
||||
"drop": {
|
||||
"dropped_ms": 1793116007019,
|
||||
"room": "cg-voice-oleganioz7",
|
||||
"session_id": "Si6UZJbAENsNExR-B1cfpIEX",
|
||||
"agent_frames_after_drop": 1
|
||||
},
|
||||
"call": {
|
||||
"tag": "call3",
|
||||
"session": {
|
||||
"url": "wss://192.168.200.12:8363",
|
||||
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ2aWRlbyI6eyJyb29tSm9pbiI6dHJ1ZSwicm9vbSI6ImNnLXZvaWNlLW9sZWdhbmlvejciLCJjYW5QdWJsaXNoIjp0cnVlLCJjYW5TdWJzY3JpYmUiOnRydWUsImNhblB1Ymxpc2hEYXRhIjp0cnVlfSwic3ViIjoidXNlci11cWZ5dWhudCIsImlzcyI6ImRldmtleSIsIm5iZiI6MTc5MzExNTY5MCwiZXhwIjoxNzkzMTE1OTkwLCJuYW1lIjoi55So5oi3In0.wXERZSpOZVIidVRq-8dkIbb7e2gPa0HUX8_ZV-kHTN4",
|
||||
"room": "cg-voice-oleganioz7",
|
||||
"session_id": "Si6UZJbAENsNExR-B1cfpIEX",
|
||||
"agent_name": "cybergril-voice-agent",
|
||||
"epoch": 4,
|
||||
"expires_at": 1793116590248
|
||||
},
|
||||
"subtitle_count": 104,
|
||||
"seq_monotonic": true,
|
||||
"agent_frames": 31510,
|
||||
"agent_audio_seconds": 315.1,
|
||||
"agent_audio_rate": 48000,
|
||||
"agent_joined_ms": 1793115690867,
|
||||
"agent_left_ms": null,
|
||||
"subtitles_file": "/opt/cybergril-hel879/evidence/call3.subtitles.jsonl",
|
||||
"agent_audio_file": "/opt/cybergril-hel879/evidence/call3.agent.wav"
|
||||
},
|
||||
"messages": [
|
||||
{
|
||||
"id": 1,
|
||||
"role": "user",
|
||||
"t": "盯着你看怎么啦",
|
||||
"status": "sent",
|
||||
"turn_id": "61605d50-17f0-4d9e-b407-60574304a827"
|
||||
},
|
||||
{
|
||||
"id": 2,
|
||||
"role": "companion",
|
||||
"t": "没怎么啦,工程师。你盯着看,我就当你在检查我有没有乱动。",
|
||||
"status": "sent",
|
||||
"turn_id": "61605d50-17f0-4d9e-b407-60574304a827"
|
||||
},
|
||||
{
|
||||
"id": 3,
|
||||
"role": "user",
|
||||
"t": "难得看你这么有意思的样子吗 烈火军校啊,朝阳啊这种类型我都是那种比较呃豪爽,比较开朗的那种类型,阳光大女孩那种感觉就",
|
||||
"status": "sent",
|
||||
"turn_id": "eb182bcd-3441-42d8-ba60-9eced3a6a5a5"
|
||||
},
|
||||
{
|
||||
"id": 4,
|
||||
"role": "companion",
|
||||
"t": "原来你是那种阳光大女孩的类型啊,难怪感觉你说话都透着一股豪爽劲儿。",
|
||||
"status": "sent",
|
||||
"turn_id": "eb182bcd-3441-42d8-ba60-9eced3a6a5a5"
|
||||
},
|
||||
{
|
||||
"id": 5,
|
||||
"role": "user",
|
||||
"t": "怎么还有没事的",
|
||||
"status": "sent",
|
||||
"turn_id": "0e1a5226-4ca6-44bb-a343-39647f0112e3"
|
||||
},
|
||||
{
|
||||
"id": 6,
|
||||
"role": "companion",
|
||||
"t": "哈哈,因为我在认真听你说话呀。",
|
||||
"status": "sent",
|
||||
"turn_id": "0e1a5226-4ca6-44bb-a343-39647f0112e3"
|
||||
},
|
||||
{
|
||||
"id": 7,
|
||||
"role": "user",
|
||||
"t": "是我不够努力吗",
|
||||
"status": "cancelled",
|
||||
"turn_id": "47d8d0ce-7ac7-4202-9757-64f5f4fb1300"
|
||||
},
|
||||
{
|
||||
"id": 8,
|
||||
"role": "user",
|
||||
"t": "没错,我就是个笨蛋派大星,我们一起去抓水母吧,我们一起度过快乐的一天",
|
||||
"status": "sent",
|
||||
"turn_id": "b72de17e-bf42-470e-b396-c219bd7593f9"
|
||||
},
|
||||
{
|
||||
"id": 9,
|
||||
"role": "companion",
|
||||
"t": "好呀,那我们这就出发去抓水母!不过我可不想住进那个菠萝屋,我只喜欢在海边晒太阳。",
|
||||
"status": "sent",
|
||||
"turn_id": "b72de17e-bf42-470e-b396-c219bd7593f9"
|
||||
},
|
||||
{
|
||||
"id": 10,
|
||||
"role": "user",
|
||||
"t": "天雷滚滚,我好怕怕劈的我浑身掉渣渣,突破天劫,我笑哈哈逆天改命,我吹喇叭滴答滴答,滴滴答",
|
||||
"status": "sent",
|
||||
"turn_id": "baa6c5c7-b483-49d4-905c-d6b7e5dd7786"
|
||||
},
|
||||
{
|
||||
"id": 11,
|
||||
"role": "companion",
|
||||
"t": "哈哈,你唱得还挺有节奏感的!",
|
||||
"status": "sent",
|
||||
"turn_id": "baa6c5c7-b483-49d4-905c-d6b7e5dd7786"
|
||||
},
|
||||
{
|
||||
"id": 12,
|
||||
"role": "user",
|
||||
"t": "你是不是早就想睡我了呀",
|
||||
"status": "sent",
|
||||
"turn_id": "a91bbbb6-45b0-4671-84a2-027cc194f420"
|
||||
},
|
||||
{
|
||||
"id": 13,
|
||||
"role": "companion",
|
||||
"t": "哈哈,你思维跳跃得太快了,我都跟不上。",
|
||||
"status": "sent",
|
||||
"turn_id": "a91bbbb6-45b0-4671-84a2-027cc194f420"
|
||||
},
|
||||
{
|
||||
"id": 14,
|
||||
"role": "user",
|
||||
"t": "盯着你看怎么啦",
|
||||
"status": "sent",
|
||||
"turn_id": "5bd95c66-b42b-4571-bfc2-fbf376c90747"
|
||||
},
|
||||
{
|
||||
"id": 15,
|
||||
"role": "companion",
|
||||
"t": "没",
|
||||
"status": "sent",
|
||||
"turn_id": "5bd95c66-b42b-4571-bfc2-fbf376c90747"
|
||||
},
|
||||
{
|
||||
"id": 16,
|
||||
"role": "user",
|
||||
"t": "师傅,哎,这取经路比高,老庄种地还苦,俺老猪饿的能吞下石龙素包子,猴哥,你筋斗云块,要不先去化个缘",
|
||||
"status": "sent",
|
||||
"turn_id": "9bba6412-6679-48c2-9f1c-4bfc07f58aea"
|
||||
},
|
||||
{
|
||||
"id": 17,
|
||||
"role": "companion",
|
||||
"t": "师傅,",
|
||||
"status": "sent",
|
||||
"turn_id": "9bba6412-6679-48c2-9f1c-4bfc07f58aea"
|
||||
},
|
||||
{
|
||||
"id": 18,
|
||||
"role": "user",
|
||||
"t": "俺老孙来也,俺乃500年前大闹天宫的齐天大圣孙悟空,这里山势险峻,只怕藏有妖精妖怪,哪里逃吃?俺老孙吧",
|
||||
"status": "sent",
|
||||
"turn_id": "16006868-5ee7-49cc-b9c9-1a8dcfe74d08"
|
||||
},
|
||||
{
|
||||
"id": 19,
|
||||
"role": "companion",
|
||||
"t": "好",
|
||||
"status": "sent",
|
||||
"turn_id": "16006868-5ee7-49cc-b9c9-1a8dcfe74d08"
|
||||
},
|
||||
{
|
||||
"id": 20,
|
||||
"role": "user",
|
||||
"t": "没错,我就是个笨蛋派大星,我们一起去抓水母吧,我们一起度过快乐的一天",
|
||||
"status": "sent",
|
||||
"turn_id": "fdf28a03-19a8-4fcb-ba8c-24587736c3f0"
|
||||
},
|
||||
{
|
||||
"id": 21,
|
||||
"role": "companion",
|
||||
"t": "好",
|
||||
"status": "sent",
|
||||
"turn_id": "fdf28a03-19a8-4fcb-ba8c-24587736c3f0"
|
||||
},
|
||||
{
|
||||
"id": 22,
|
||||
"role": "user",
|
||||
"t": "你是不是早就想睡我了呀",
|
||||
"status": "sent",
|
||||
"turn_id": "623bab59-0edc-4751-9feb-a9a7e4a11233"
|
||||
},
|
||||
{
|
||||
"id": 23,
|
||||
"role": "user",
|
||||
"t": "(文字通道)我改用打字了,这条应该立刻打断你正在说的话。",
|
||||
"status": "cancelled",
|
||||
"turn_id": "cb1bbe27-795f-45e3-b7bf-f2d6371c0830"
|
||||
},
|
||||
{
|
||||
"id": 25,
|
||||
"role": "companion",
|
||||
"t": "Considering the limited time by the user, I have to give the",
|
||||
"status": "sent",
|
||||
"turn_id": "623bab59-0edc-4751-9feb-a9a7e4a11233"
|
||||
}
|
||||
],
|
||||
"receipts": [
|
||||
{
|
||||
"message_id": 9,
|
||||
"turn_id": "b72de17e-bf42-470e-b396-c219bd7593f9",
|
||||
"ack_at": 1793115457081,
|
||||
"state": "judged"
|
||||
},
|
||||
{
|
||||
"message_id": 11,
|
||||
"turn_id": "baa6c5c7-b483-49d4-905c-d6b7e5dd7786",
|
||||
"ack_at": 1793115476109,
|
||||
"state": "judged"
|
||||
},
|
||||
{
|
||||
"message_id": 13,
|
||||
"turn_id": "a91bbbb6-45b0-4671-84a2-027cc194f420",
|
||||
"ack_at": 1793115489069,
|
||||
"state": "judged"
|
||||
},
|
||||
{
|
||||
"message_id": 15,
|
||||
"turn_id": "5bd95c66-b42b-4571-bfc2-fbf376c90747",
|
||||
"ack_at": 1793115501163,
|
||||
"state": "judged"
|
||||
},
|
||||
{
|
||||
"message_id": 17,
|
||||
"turn_id": "9bba6412-6679-48c2-9f1c-4bfc07f58aea",
|
||||
"ack_at": 1793115715591,
|
||||
"state": "judged"
|
||||
},
|
||||
{
|
||||
"message_id": 19,
|
||||
"turn_id": "16006868-5ee7-49cc-b9c9-1a8dcfe74d08",
|
||||
"ack_at": 1793115816209,
|
||||
"state": "judged"
|
||||
},
|
||||
{
|
||||
"message_id": 21,
|
||||
"turn_id": "fdf28a03-19a8-4fcb-ba8c-24587736c3f0",
|
||||
"ack_at": 1793115908179,
|
||||
"state": "judged"
|
||||
},
|
||||
{
|
||||
"message_id": 25,
|
||||
"turn_id": "623bab59-0edc-4751-9feb-a9a7e4a11233",
|
||||
"ack_at": 1793116005932,
|
||||
"state": "pending"
|
||||
}
|
||||
],
|
||||
"budget": {
|
||||
"at_ms": 1793116007051,
|
||||
"token_usage": [
|
||||
{
|
||||
"day": "2026-10-27",
|
||||
"scene": "dialogue_main",
|
||||
"used": 42717
|
||||
}
|
||||
],
|
||||
"request_usage": [
|
||||
{
|
||||
"day": "2026-10-27",
|
||||
"category": "dialogue",
|
||||
"requests": 14
|
||||
}
|
||||
],
|
||||
"budget_total": [
|
||||
{
|
||||
"key": "total_requests",
|
||||
"value": 14
|
||||
},
|
||||
{
|
||||
"key": "total_tokens",
|
||||
"value": 42717
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,104 @@
|
||||
{"v": 2, "seq": 1, "kind": "interim", "role": "user", "text": "师", "_at_ms": 1793115691554}
|
||||
{"v": 2, "seq": 2, "kind": "interim", "role": "user", "text": "傅", "_at_ms": 1793115692163}
|
||||
{"v": 2, "seq": 3, "kind": "interim", "role": "user", "text": "哎这", "_at_ms": 1793115692756}
|
||||
{"v": 2, "seq": 4, "kind": "interim", "role": "user", "text": "取经", "_at_ms": 1793115693359}
|
||||
{"v": 2, "seq": 5, "kind": "interim", "role": "user", "text": "路比", "_at_ms": 1793115693964}
|
||||
{"v": 2, "seq": 6, "kind": "interim", "role": "user", "text": "高老", "_at_ms": 1793115694564}
|
||||
{"v": 2, "seq": 7, "kind": "interim", "role": "user", "text": "庄种", "_at_ms": 1793115695157}
|
||||
{"v": 2, "seq": 8, "kind": "interim", "role": "user", "text": "地还", "_at_ms": 1793115695762}
|
||||
{"v": 2, "seq": 9, "kind": "interim", "role": "user", "text": "苦俺", "_at_ms": 1793115696359}
|
||||
{"v": 2, "seq": 10, "kind": "interim", "role": "user", "text": "老中", "_at_ms": 1793115696958}
|
||||
{"v": 2, "seq": 11, "kind": "interim", "role": "user", "text": "饿的能", "_at_ms": 1793115697557}
|
||||
{"v": 2, "seq": 12, "kind": "interim", "role": "user", "text": "吞下", "_at_ms": 1793115698168}
|
||||
{"v": 2, "seq": 13, "kind": "interim", "role": "user", "text": "石龙", "_at_ms": 1793115698760}
|
||||
{"v": 2, "seq": 14, "kind": "interim", "role": "user", "text": "素包", "_at_ms": 1793115699353}
|
||||
{"v": 2, "seq": 15, "kind": "interim", "role": "user", "text": "子", "_at_ms": 1793115699967}
|
||||
{"v": 2, "seq": 16, "kind": "interim", "role": "user", "text": "猴哥", "_at_ms": 1793115700562}
|
||||
{"v": 2, "seq": 17, "kind": "interim", "role": "user", "text": "你筋", "_at_ms": 1793115701159}
|
||||
{"v": 2, "seq": 18, "kind": "interim", "role": "user", "text": "斗云", "_at_ms": 1793115701768}
|
||||
{"v": 2, "seq": 19, "kind": "interim", "role": "user", "text": "快", "_at_ms": 1793115702352}
|
||||
{"v": 2, "seq": 20, "kind": "interim", "role": "user", "text": "要不", "_at_ms": 1793115702961}
|
||||
{"v": 2, "seq": 21, "kind": "interim", "role": "user", "text": "先", "_at_ms": 1793115703557}
|
||||
{"v": 2, "seq": 22, "kind": "interim", "role": "user", "text": "去画个", "_at_ms": 1793115704166}
|
||||
{"v": 2, "seq": 23, "kind": "user_final", "role": "user", "text": "师傅,哎,这取经路比高,老庄种地还苦,俺老猪饿的能吞下石龙素包子,猴哥,你筋斗云块,要不先去化个缘", "_at_ms": 1793115706500}
|
||||
{"v": 2, "seq": 24, "kind": "turn_start", "role": "assistant", "text": "", "speech_id": "speech_ba7b3f730ffd", "_at_ms": 1793115710205}
|
||||
{"v": 2, "seq": 25, "kind": "assistant_interim", "role": "assistant", "text": "师傅", "speech_id": "speech_ba7b3f730ffd", "_at_ms": 1793115711789}
|
||||
{"v": 2, "seq": 26, "kind": "assistant_interim", "role": "assistant", "text": "师傅,", "speech_id": "speech_ba7b3f730ffd", "_at_ms": 1793115711850}
|
||||
{"v": 2, "seq": 27, "kind": "assistant_final", "role": "assistant", "text": "师傅,", "speech_id": "speech_ba7b3f730ffd", "turn_id": "9bba6412-6679-48c2-9f1c-4bfc07f58aea", "_at_ms": 1793115715589}
|
||||
{"v": 2, "seq": 28, "kind": "turn_end", "role": "assistant", "text": "", "speech_id": "speech_ba7b3f730ffd", "turn_id": "9bba6412-6679-48c2-9f1c-4bfc07f58aea", "_at_ms": 1793115715590}
|
||||
{"v": 2, "seq": 29, "kind": "interim", "role": "user", "text": "俺老", "_at_ms": 1793115792459}
|
||||
{"v": 2, "seq": 30, "kind": "interim", "role": "user", "text": "孙来", "_at_ms": 1793115793061}
|
||||
{"v": 2, "seq": 31, "kind": "interim", "role": "user", "text": "也俺", "_at_ms": 1793115793659}
|
||||
{"v": 2, "seq": 32, "kind": "interim", "role": "user", "text": "乃五百", "_at_ms": 1793115794261}
|
||||
{"v": 2, "seq": 33, "kind": "interim", "role": "user", "text": "年前", "_at_ms": 1793115794859}
|
||||
{"v": 2, "seq": 34, "kind": "interim", "role": "user", "text": "大闹", "_at_ms": 1793115795470}
|
||||
{"v": 2, "seq": 35, "kind": "interim", "role": "user", "text": "天宫的", "_at_ms": 1793115796055}
|
||||
{"v": 2, "seq": 36, "kind": "interim", "role": "user", "text": "齐天", "_at_ms": 1793115796661}
|
||||
{"v": 2, "seq": 37, "kind": "interim", "role": "user", "text": "霸圣", "_at_ms": 1793115797263}
|
||||
{"v": 2, "seq": 38, "kind": "interim", "role": "user", "text": "孙悟", "_at_ms": 1793115797864}
|
||||
{"v": 2, "seq": 39, "kind": "interim", "role": "user", "text": "空这", "_at_ms": 1793115798464}
|
||||
{"v": 2, "seq": 40, "kind": "interim", "role": "user", "text": "里山", "_at_ms": 1793115799067}
|
||||
{"v": 2, "seq": 41, "kind": "interim", "role": "user", "text": "势险", "_at_ms": 1793115799657}
|
||||
{"v": 2, "seq": 42, "kind": "interim", "role": "user", "text": "峻", "_at_ms": 1793115800262}
|
||||
{"v": 2, "seq": 43, "kind": "interim", "role": "user", "text": "只怕藏", "_at_ms": 1793115800858}
|
||||
{"v": 2, "seq": 44, "kind": "interim", "role": "user", "text": "有妖", "_at_ms": 1793115801462}
|
||||
{"v": 2, "seq": 45, "kind": "interim", "role": "user", "text": "精妖", "_at_ms": 1793115802053}
|
||||
{"v": 2, "seq": 46, "kind": "interim", "role": "user", "text": "怪", "_at_ms": 1793115802654}
|
||||
{"v": 2, "seq": 47, "kind": "interim", "role": "user", "text": "哪里", "_at_ms": 1793115803271}
|
||||
{"v": 2, "seq": 48, "kind": "interim", "role": "user", "text": "逃", "_at_ms": 1793115803858}
|
||||
{"v": 2, "seq": 49, "kind": "interim", "role": "user", "text": "吃完老", "_at_ms": 1793115804464}
|
||||
{"v": 2, "seq": 50, "kind": "interim", "role": "user", "text": "我所", "_at_ms": 1793115805066}
|
||||
{"v": 2, "seq": 51, "kind": "interim", "role": "user", "text": "一", "_at_ms": 1793115805654}
|
||||
{"v": 2, "seq": 52, "kind": "user_final", "role": "user", "text": "俺老孙来也,俺乃500年前大闹天宫的齐天大圣孙悟空,这里山势险峻,只怕藏有妖精妖怪,哪里逃吃?俺老孙吧", "_at_ms": 1793115807317}
|
||||
{"v": 2, "seq": 53, "kind": "turn_start", "role": "assistant", "text": "", "speech_id": "speech_d1c8f4816b10", "_at_ms": 1793115810983}
|
||||
{"v": 2, "seq": 54, "kind": "assistant_interim", "role": "assistant", "text": "好", "speech_id": "speech_d1c8f4816b10", "_at_ms": 1793115812231}
|
||||
{"v": 2, "seq": 55, "kind": "assistant_final", "role": "assistant", "text": "好", "speech_id": "speech_d1c8f4816b10", "turn_id": "16006868-5ee7-49cc-b9c9-1a8dcfe74d08", "_at_ms": 1793115816208}
|
||||
{"v": 2, "seq": 56, "kind": "turn_end", "role": "assistant", "text": "", "speech_id": "speech_d1c8f4816b10", "turn_id": "16006868-5ee7-49cc-b9c9-1a8dcfe74d08", "_at_ms": 1793115816213}
|
||||
{"v": 2, "seq": 57, "kind": "interim", "role": "user", "text": "没", "_at_ms": 1793115893204}
|
||||
{"v": 2, "seq": 58, "kind": "interim", "role": "user", "text": "错我", "_at_ms": 1793115893809}
|
||||
{"v": 2, "seq": 59, "kind": "interim", "role": "user", "text": "就是个笨", "_at_ms": 1793115894415}
|
||||
{"v": 2, "seq": 60, "kind": "interim", "role": "user", "text": "蛋", "_at_ms": 1793115895004}
|
||||
{"v": 2, "seq": 61, "kind": "interim", "role": "user", "text": "派大", "_at_ms": 1793115895614}
|
||||
{"v": 2, "seq": 62, "kind": "interim", "role": "user", "text": "星我们一", "_at_ms": 1793115896206}
|
||||
{"v": 2, "seq": 63, "kind": "interim", "role": "user", "text": "起去抓", "_at_ms": 1793115896811}
|
||||
{"v": 2, "seq": 64, "kind": "interim", "role": "user", "text": "水母", "_at_ms": 1793115897406}
|
||||
{"v": 2, "seq": 65, "kind": "interim", "role": "user", "text": "吧我们", "_at_ms": 1793115898018}
|
||||
{"v": 2, "seq": 66, "kind": "interim", "role": "user", "text": "一起度", "_at_ms": 1793115898608}
|
||||
{"v": 2, "seq": 67, "kind": "interim", "role": "user", "text": "过快乐的一", "_at_ms": 1793115899211}
|
||||
{"v": 2, "seq": 68, "kind": "user_final", "role": "user", "text": "没错,我就是个笨蛋派大星,我们一起去抓水母吧,我们一起度过快乐的一天", "_at_ms": 1793115901261}
|
||||
{"v": 2, "seq": 69, "kind": "turn_start", "role": "assistant", "text": "", "speech_id": "speech_8ac7cd94c5db", "_at_ms": 1793115901269}
|
||||
{"v": 2, "seq": 70, "kind": "assistant_interim", "role": "assistant", "text": "好", "speech_id": "speech_8ac7cd94c5db", "_at_ms": 1793115902769}
|
||||
{"v": 2, "seq": 71, "kind": "assistant_final", "role": "assistant", "text": "好", "speech_id": "speech_8ac7cd94c5db", "turn_id": "fdf28a03-19a8-4fcb-ba8c-24587736c3f0", "_at_ms": 1793115908179}
|
||||
{"v": 2, "seq": 72, "kind": "turn_end", "role": "assistant", "text": "", "speech_id": "speech_8ac7cd94c5db", "turn_id": "fdf28a03-19a8-4fcb-ba8c-24587736c3f0", "_at_ms": 1793115908181}
|
||||
{"v": 2, "seq": 73, "kind": "interim", "role": "user", "text": "你是不是", "_at_ms": 1793115991657}
|
||||
{"v": 2, "seq": 74, "kind": "interim", "role": "user", "text": "早就想", "_at_ms": 1793115992268}
|
||||
{"v": 2, "seq": 75, "kind": "interim", "role": "user", "text": "睡我", "_at_ms": 1793115992857}
|
||||
{"v": 2, "seq": 76, "kind": "interim", "role": "user", "text": "了", "_at_ms": 1793115993462}
|
||||
{"v": 2, "seq": 77, "kind": "user_final", "role": "user", "text": "你是不是早就想睡我了呀", "_at_ms": 1793115994404}
|
||||
{"v": 2, "seq": 78, "kind": "turn_start", "role": "assistant", "text": "", "speech_id": "speech_9aa32dc387c3", "_at_ms": 1793115994412}
|
||||
{"v": 2, "seq": 79, "kind": "assistant_interim", "role": "assistant", "text": "Considering", "speech_id": "speech_9aa32dc387c3", "_at_ms": 1793115994844}
|
||||
{"v": 2, "seq": 80, "kind": "assistant_interim", "role": "assistant", "text": "Considering the", "speech_id": "speech_9aa32dc387c3", "_at_ms": 1793115994878}
|
||||
{"v": 2, "seq": 81, "kind": "assistant_interim", "role": "assistant", "text": "Considering the limited", "speech_id": "speech_9aa32dc387c3", "_at_ms": 1793115994911}
|
||||
{"v": 2, "seq": 82, "kind": "assistant_interim", "role": "assistant", "text": "Considering the limited time", "speech_id": "speech_9aa32dc387c3", "_at_ms": 1793115994944}
|
||||
{"v": 2, "seq": 83, "kind": "assistant_interim", "role": "assistant", "text": "Considering the limited time by", "speech_id": "speech_9aa32dc387c3", "_at_ms": 1793115994977}
|
||||
{"v": 2, "seq": 84, "kind": "assistant_interim", "role": "assistant", "text": "Considering the limited time by the", "speech_id": "speech_9aa32dc387c3", "_at_ms": 1793115995010}
|
||||
{"v": 2, "seq": 85, "kind": "assistant_interim", "role": "assistant", "text": "Considering the limited time by the user", "speech_id": "speech_9aa32dc387c3", "_at_ms": 1793115995044}
|
||||
{"v": 2, "seq": 86, "kind": "assistant_interim", "role": "assistant", "text": "Considering the limited time by the user,", "speech_id": "speech_9aa32dc387c3", "_at_ms": 1793115995077}
|
||||
{"v": 2, "seq": 87, "kind": "assistant_interim", "role": "assistant", "text": "Considering the limited time by the user, I", "speech_id": "speech_9aa32dc387c3", "_at_ms": 1793115995111}
|
||||
{"v": 2, "seq": 88, "kind": "assistant_interim", "role": "assistant", "text": "Considering the limited time by the user, I have", "speech_id": "speech_9aa32dc387c3", "_at_ms": 1793115995144}
|
||||
{"v": 2, "seq": 89, "kind": "assistant_interim", "role": "assistant", "text": "Considering the limited time by the user, I have to", "speech_id": "speech_9aa32dc387c3", "_at_ms": 1793115995178}
|
||||
{"v": 2, "seq": 90, "kind": "assistant_interim", "role": "assistant", "text": "Considering the limited time by the user, I have to give", "speech_id": "speech_9aa32dc387c3", "_at_ms": 1793115995212}
|
||||
{"v": 2, "seq": 91, "kind": "assistant_interim", "role": "assistant", "text": "Considering the limited time by the user, I have to give the", "speech_id": "speech_9aa32dc387c3", "_at_ms": 1793115995245}
|
||||
{"v": 2, "seq": 92, "kind": "assistant_interim", "role": "assistant", "text": "Considering the limited time by the user, I have to give the solution", "speech_id": "speech_9aa32dc387c3", "_at_ms": 1793115995278}
|
||||
{"v": 2, "seq": 93, "kind": "assistant_interim", "role": "assistant", "text": "Considering the limited time by the user, I have to give the solution based", "speech_id": "speech_9aa32dc387c3", "_at_ms": 1793115995312}
|
||||
{"v": 2, "seq": 94, "kind": "assistant_interim", "role": "assistant", "text": "Considering the limited time by the user, I have to give the solution based on", "speech_id": "speech_9aa32dc387c3", "_at_ms": 1793115995345}
|
||||
{"v": 2, "seq": 95, "kind": "assistant_interim", "role": "assistant", "text": "Considering the limited time by the user, I have to give the solution based on the", "speech_id": "speech_9aa32dc387c3", "_at_ms": 1793115995378}
|
||||
{"v": 2, "seq": 96, "kind": "assistant_interim", "role": "assistant", "text": "Considering the limited time by the user, I have to give the solution based on the thinking", "speech_id": "speech_9aa32dc387c3", "_at_ms": 1793115995412}
|
||||
{"v": 2, "seq": 97, "kind": "assistant_interim", "role": "assistant", "text": "Considering the limited time by the user, I have to give the solution based on the thinking directly", "speech_id": "speech_9aa32dc387c3", "_at_ms": 1793115995445}
|
||||
{"v": 2, "seq": 98, "kind": "assistant_interim", "role": "assistant", "text": "Considering the limited time by the user, I have to give the solution based on the thinking directly now", "speech_id": "speech_9aa32dc387c3", "_at_ms": 1793115995478}
|
||||
{"v": 2, "seq": 99, "kind": "assistant_interim", "role": "assistant", "text": "Considering the limited time by the user, I have to give the solution based on the thinking directly now.", "speech_id": "speech_9aa32dc387c3", "_at_ms": 1793115995511}
|
||||
{"v": 2, "seq": 100, "kind": "assistant_interim", "role": "assistant", "text": "Considering the limited time by the user, I have to give the solution based on the thinking directly now.\n", "speech_id": "speech_9aa32dc387c3", "_at_ms": 1793115995549}
|
||||
{"v": 2, "seq": 101, "kind": "assistant_interim", "role": "assistant", "text": "Considering the limited time by the user, I have to give the solution based on the thinking directly now.\n</think>", "speech_id": "speech_9aa32dc387c3", "_at_ms": 1793115995583}
|
||||
{"v": 2, "seq": 102, "kind": "assistant_interim", "role": "assistant", "text": "Considering the limited time by the user, I have to give the solution based on the thinking directly now.\n</think>\n\n", "speech_id": "speech_9aa32dc387c3", "_at_ms": 1793115995614}
|
||||
{"v": 2, "seq": 103, "kind": "assistant_final", "role": "assistant", "text": "Considering the limited time by the user, I have to give the solution based on the thinking directly now.\n</think>\n\n", "speech_id": "speech_9aa32dc387c3", "turn_id": "623bab59-0edc-4751-9feb-a9a7e4a11233", "_at_ms": 1793116005934}
|
||||
{"v": 2, "seq": 104, "kind": "turn_end", "role": "assistant", "text": "", "speech_id": "speech_9aa32dc387c3", "turn_id": "623bab59-0edc-4751-9feb-a9a7e4a11233", "_at_ms": 1793116005935}
|
||||
@@ -0,0 +1,2 @@
|
||||
WINDOW_START=2026-10-27T15:26:54Z
|
||||
WINDOW_END=2026-10-27T15:58:10Z
|
||||
@@ -0,0 +1,409 @@
|
||||
{"message": "starting worker", "level": "INFO", "name": "livekit.agents", "version": "1.8.8", "rtc-version": "1.1.20", "pid": 8800, "timestamp": "2026-10-27T15:21:02.628498+00:00"}
|
||||
{"message": "plugin registered", "level": "INFO", "name": "livekit.agents", "plugin": "livekit.plugins.silero", "version": "1.8.8", "pid": 8800, "timestamp": "2026-10-27T15:21:02.628622+00:00"}
|
||||
{"message": "preloading plugins", "level": "INFO", "name": "livekit.agents", "packages": ["livekit.plugins.silero", "livekit.agents.ipc._preload", "livekit.agents.ipc._preload_freeze"], "pid": 8800, "timestamp": "2026-10-27T15:21:02.628690+00:00"}
|
||||
{"message": "HTTP server listening on :8082", "level": "INFO", "name": "livekit.agents", "pid": 8800, "timestamp": "2026-10-27T15:21:02.632394+00:00"}
|
||||
{"message": "initializing process", "level": "INFO", "name": "livekit.agents", "pid": 8879, "timestamp": "2026-10-27T15:21:03.868641+00:00"}
|
||||
{"message": "initializing process", "level": "INFO", "name": "livekit.agents", "pid": 8881, "timestamp": "2026-10-27T15:21:03.871820+00:00"}
|
||||
{"message": "initializing process", "level": "INFO", "name": "livekit.agents", "pid": 8883, "timestamp": "2026-10-27T15:21:03.874482+00:00"}
|
||||
{"message": "initializing process", "level": "INFO", "name": "livekit.agents", "pid": 8885, "timestamp": "2026-10-27T15:21:03.877329+00:00"}
|
||||
{"message": "process initialized", "level": "INFO", "name": "livekit.agents", "pid": 8885, "elapsed_time": 0.14, "timestamp": "2026-10-27T15:21:04.013188+00:00"}
|
||||
{"message": "process initialized", "level": "INFO", "name": "livekit.agents", "pid": 8883, "elapsed_time": 0.14, "timestamp": "2026-10-27T15:21:04.013380+00:00"}
|
||||
{"message": "process initialized", "level": "INFO", "name": "livekit.agents", "pid": 8879, "elapsed_time": 0.14, "timestamp": "2026-10-27T15:21:04.013613+00:00"}
|
||||
{"message": "process initialized", "level": "INFO", "name": "livekit.agents", "pid": 8881, "elapsed_time": 0.14, "timestamp": "2026-10-27T15:21:04.016022+00:00"}
|
||||
/opt/voice-agent/agent/venv/lib/python3.12/site-packages/jwt/api_jwt.py:149: InsecureKeyLengthWarning: The HMAC key is 28 bytes long, which is below the minimum recommended length of 32 bytes for SHA256. See RFC 7518 Section 3.2.
|
||||
return self._jws.encode(
|
||||
{"message": "registered worker", "level": "INFO", "name": "livekit.agents", "agent_name": "cybergril-voice-agent", "deployment": "", "id": "AW_LGViCVagSNNu", "url": "ws://127.0.0.1:7880", "region": "", "protocol": 17, "pid": 8800, "timestamp": "2026-10-27T15:21:04.039801+00:00"}
|
||||
{"message": "received job request", "level": "INFO", "name": "livekit.agents", "job_id": "AJ_dcfbVLNh9cxc", "dispatch_id": "AD_pFPtM5kSSpZH", "room": "probe-room-2", "room_id": "RM_mNZagsczYXao", "agent_name": "cybergril-voice-agent", "resuming": false, "enable_recording": false, "pid": 8800, "timestamp": "2026-10-27T15:28:57.444695+00:00"}
|
||||
{"message": "initializing process", "level": "INFO", "name": "livekit.agents", "pid": 10801, "timestamp": "2026-10-27T15:28:57.518855+00:00"}
|
||||
{"message": "process initialized", "level": "INFO", "name": "livekit.agents", "pid": 10801, "elapsed_time": 0.12, "timestamp": "2026-10-27T15:28:57.639650+00:00"}
|
||||
Nvidia Decoder is supported.
|
||||
{"message": "adaptive interruption is disabled by default in production mode", "level": "INFO", "name": "livekit.agents", "pid": 8885, "job_id": "AJ_dcfbVLNh9cxc", "room": "probe-room-2", "room_id": "RM_mNZagsczYXao", "timestamp": "2026-10-27T15:28:57.893684+00:00"}
|
||||
{"message": "failed to emit event conversation_item_added\nTraceback (most recent call last):\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/rtc/event_emitter.py\", line 70, in emit\n callback(*callback_args)\n File \"/opt/voice-agent-cybergril/cybergril/voice/worker.py\", line 193, in _on_item\n if ev.item.role == \"assistant\":\n ^^^^^^^^^^^^\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/pydantic/main.py\", line 1105, in __getattr__\n raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}')\nAttributeError: 'AgentHandoff' object has no attribute 'role'", "level": "ERROR", "name": "livekit", "exc_info": "Traceback (most recent call last):\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/rtc/event_emitter.py\", line 70, in emit\n callback(*callback_args)\n File \"/opt/voice-agent-cybergril/cybergril/voice/worker.py\", line 193, in _on_item\n if ev.item.role == \"assistant\":\n ^^^^^^^^^^^^\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/pydantic/main.py\", line 1105, in __getattr__\n raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}')\nAttributeError: 'AgentHandoff' object has no attribute 'role'", "pid": 8885, "job_id": "AJ_dcfbVLNh9cxc", "room": "probe-room-2", "room_id": "RM_mNZagsczYXao", "timestamp": "2026-10-27T15:28:57.895149+00:00"}
|
||||
[cybergril-worker] session started (api=http://127.0.0.1:8360, voice=female_soft, agent_name=cybergril-voice-agent)
|
||||
{"message": "received job request", "level": "INFO", "name": "livekit.agents", "job_id": "AJ_FBBgf5Si2JYd", "dispatch_id": "AD_iJTKQsucFwSK", "room": "probe-room-3", "room_id": "RM_msdxb3QWFMYf", "agent_name": "cybergril-voice-agent", "resuming": false, "enable_recording": false, "pid": 8800, "timestamp": "2026-10-27T15:32:32.446385+00:00"}
|
||||
{"message": "initializing process", "level": "INFO", "name": "livekit.agents", "pid": 11093, "timestamp": "2026-10-27T15:32:32.549290+00:00"}
|
||||
{"message": "process initialized", "level": "INFO", "name": "livekit.agents", "pid": 11093, "elapsed_time": 0.12, "timestamp": "2026-10-27T15:32:32.665948+00:00"}
|
||||
Nvidia Decoder is supported.
|
||||
{"message": "adaptive interruption is disabled by default in production mode", "level": "INFO", "name": "livekit.agents", "pid": 8883, "job_id": "AJ_FBBgf5Si2JYd", "room": "probe-room-3", "room_id": "RM_msdxb3QWFMYf", "timestamp": "2026-10-27T15:32:32.853330+00:00"}
|
||||
{"message": "failed to emit event conversation_item_added\nTraceback (most recent call last):\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/rtc/event_emitter.py\", line 70, in emit\n callback(*callback_args)\n File \"/opt/voice-agent-cybergril/cybergril/voice/worker.py\", line 193, in _on_item\n if ev.item.role == \"assistant\":\n ^^^^^^^^^^^^\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/pydantic/main.py\", line 1105, in __getattr__\n raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}')\nAttributeError: 'AgentHandoff' object has no attribute 'role'", "level": "ERROR", "name": "livekit", "exc_info": "Traceback (most recent call last):\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/rtc/event_emitter.py\", line 70, in emit\n callback(*callback_args)\n File \"/opt/voice-agent-cybergril/cybergril/voice/worker.py\", line 193, in _on_item\n if ev.item.role == \"assistant\":\n ^^^^^^^^^^^^\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/pydantic/main.py\", line 1105, in __getattr__\n raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}')\nAttributeError: 'AgentHandoff' object has no attribute 'role'", "pid": 8883, "job_id": "AJ_FBBgf5Si2JYd", "room": "probe-room-3", "room_id": "RM_msdxb3QWFMYf", "timestamp": "2026-10-27T15:32:32.855790+00:00"}
|
||||
[cybergril-worker] session started (api=http://127.0.0.1:8360, voice=female_soft, agent_name=cybergril-voice-agent)
|
||||
{"message": "received job request", "level": "INFO", "name": "livekit.agents", "job_id": "AJ_QhLhdpZKohT3", "dispatch_id": "AD_6Esm9sgx9sbT", "room": "cg-voice-74blnuc9c6", "room_id": "RM_q3vSy5gNpvMA", "agent_name": "cybergril-voice-agent", "resuming": false, "enable_recording": false, "pid": 8800, "timestamp": "2026-10-27T15:32:39.512686+00:00"}
|
||||
{"message": "initializing process", "level": "INFO", "name": "livekit.agents", "pid": 11326, "timestamp": "2026-10-27T15:32:39.616162+00:00"}
|
||||
{"message": "process initialized", "level": "INFO", "name": "livekit.agents", "pid": 11326, "elapsed_time": 0.12, "timestamp": "2026-10-27T15:32:39.737803+00:00"}
|
||||
Nvidia Decoder is supported.
|
||||
{"message": "adaptive interruption is disabled by default in production mode", "level": "INFO", "name": "livekit.agents", "pid": 8879, "job_id": "AJ_QhLhdpZKohT3", "room": "cg-voice-74blnuc9c6", "room_id": "RM_q3vSy5gNpvMA", "timestamp": "2026-10-27T15:32:39.969275+00:00"}
|
||||
{"message": "failed to emit event conversation_item_added\nTraceback (most recent call last):\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/rtc/event_emitter.py\", line 70, in emit\n callback(*callback_args)\n File \"/opt/voice-agent-cybergril/cybergril/voice/worker.py\", line 193, in _on_item\n if ev.item.role == \"assistant\":\n ^^^^^^^^^^^^\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/pydantic/main.py\", line 1105, in __getattr__\n raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}')\nAttributeError: 'AgentHandoff' object has no attribute 'role'", "level": "ERROR", "name": "livekit", "exc_info": "Traceback (most recent call last):\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/rtc/event_emitter.py\", line 70, in emit\n callback(*callback_args)\n File \"/opt/voice-agent-cybergril/cybergril/voice/worker.py\", line 193, in _on_item\n if ev.item.role == \"assistant\":\n ^^^^^^^^^^^^\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/pydantic/main.py\", line 1105, in __getattr__\n raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}')\nAttributeError: 'AgentHandoff' object has no attribute 'role'", "pid": 8879, "job_id": "AJ_QhLhdpZKohT3", "room": "cg-voice-74blnuc9c6", "room_id": "RM_q3vSy5gNpvMA", "timestamp": "2026-10-27T15:32:39.971493+00:00"}
|
||||
[cybergril-worker] session started (api=http://127.0.0.1:8360, voice=female_soft, agent_name=cybergril-voice-agent)
|
||||
{"message": "livekit::rtc_engine::rtc_session:704:livekit::rtc_engine::rtc_session - publisher data channel '_reliable' closed unexpectedly", "level": "ERROR", "name": "livekit", "pid": 8879, "job_id": "AJ_QhLhdpZKohT3", "room": "cg-voice-74blnuc9c6", "room_id": "RM_q3vSy5gNpvMA", "timestamp": "2026-10-27T15:32:59.437282+00:00"}
|
||||
{"message": "process exiting", "level": "INFO", "name": "livekit.agents", "reason": "parent process shutdown", "pid": 8879, "job_id": "AJ_QhLhdpZKohT3", "room": "cg-voice-74blnuc9c6", "room_id": "RM_q3vSy5gNpvMA", "timestamp": "2026-10-27T15:33:01.444726+00:00"}
|
||||
{"message": "received job request", "level": "INFO", "name": "livekit.agents", "job_id": "AJ_4vPjEVFaLPMq", "dispatch_id": "AD_MVu9k7fFLQyy", "room": "cg-voice-qeghdnxehn", "room_id": "RM_EMAorR7C2evE", "agent_name": "cybergril-voice-agent", "resuming": false, "enable_recording": false, "pid": 8800, "timestamp": "2026-10-27T15:33:23.836716+00:00"}
|
||||
{"message": "initializing process", "level": "INFO", "name": "livekit.agents", "pid": 11830, "timestamp": "2026-10-27T15:33:23.895593+00:00"}
|
||||
{"message": "process initialized", "level": "INFO", "name": "livekit.agents", "pid": 11830, "elapsed_time": 0.12, "timestamp": "2026-10-27T15:33:24.010796+00:00"}
|
||||
Nvidia Decoder is supported.
|
||||
{"message": "RoomIO linked to participant", "level": "INFO", "name": "livekit.agents", "lk.pii.participant_identity": "user-gwhvezcz", "lk.pii.room_name": "cg-voice-qeghdnxehn", "pid": 8881, "job_id": "AJ_4vPjEVFaLPMq", "room": "cg-voice-qeghdnxehn", "room_id": "RM_EMAorR7C2evE", "timestamp": "2026-10-27T15:33:24.256405+00:00"}
|
||||
{"message": "adaptive interruption is disabled by default in production mode", "level": "INFO", "name": "livekit.agents", "pid": 8881, "job_id": "AJ_4vPjEVFaLPMq", "room": "cg-voice-qeghdnxehn", "room_id": "RM_EMAorR7C2evE", "timestamp": "2026-10-27T15:33:24.260750+00:00"}
|
||||
{"message": "failed to emit event conversation_item_added\nTraceback (most recent call last):\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/rtc/event_emitter.py\", line 70, in emit\n callback(*callback_args)\n File \"/opt/voice-agent-cybergril/cybergril/voice/worker.py\", line 193, in _on_item\n if ev.item.role == \"assistant\":\n ^^^^^^^^^^^^\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/pydantic/main.py\", line 1105, in __getattr__\n raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}')\nAttributeError: 'AgentHandoff' object has no attribute 'role'", "level": "ERROR", "name": "livekit", "exc_info": "Traceback (most recent call last):\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/rtc/event_emitter.py\", line 70, in emit\n callback(*callback_args)\n File \"/opt/voice-agent-cybergril/cybergril/voice/worker.py\", line 193, in _on_item\n if ev.item.role == \"assistant\":\n ^^^^^^^^^^^^\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/pydantic/main.py\", line 1105, in __getattr__\n raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}')\nAttributeError: 'AgentHandoff' object has no attribute 'role'", "pid": 8881, "job_id": "AJ_4vPjEVFaLPMq", "room": "cg-voice-qeghdnxehn", "room_id": "RM_EMAorR7C2evE", "timestamp": "2026-10-27T15:33:24.261961+00:00"}
|
||||
[cybergril-worker] session started (api=http://127.0.0.1:8360, voice=female_soft, agent_name=cybergril-voice-agent)
|
||||
[stt] utterance open, frame sr=24000
|
||||
[stt] interim: 盯
|
||||
[stt->session] interim_transcript: 盯
|
||||
[stt] interim: 着你看怎
|
||||
[stt->session] interim_transcript: 着你看怎
|
||||
[stt] interim: 么啦
|
||||
[stt->session] interim_transcript: 么啦
|
||||
[stt] FINAL(merged): 盯着你看怎么啦
|
||||
[stt->session] final_transcript: 盯着你看怎么啦
|
||||
[stt] interim: 难得
|
||||
[stt->session] interim_transcript: 难得
|
||||
[stt] interim: 看你这么
|
||||
[stt->session] interim_transcript: 看你这么
|
||||
[stt] interim: 有意思的
|
||||
[stt->session] interim_transcript: 有意思的
|
||||
[stt] interim: 样子
|
||||
[stt->session] interim_transcript: 样子
|
||||
[stt] FINAL(merged): 难得看你这么有意思的样子吗
|
||||
[stt->session] final_transcript: 难得看你这么有意思的样子吗
|
||||
{"message": "transcript arrives after turn has been committed. consider raising `min_delay` in the endpointing options to accommodate a slow stt. subsequent occurrences will log at debug level.", "level": "WARNING", "name": "livekit.agents", "pid": 8881, "job_id": "AJ_4vPjEVFaLPMq", "room": "cg-voice-qeghdnxehn", "room_id": "RM_EMAorR7C2evE", "timestamp": "2026-10-27T15:33:30.501478+00:00"}
|
||||
[stt] interim: 烈会军校
|
||||
[stt->session] interim_transcript: 烈会军校
|
||||
[stt] interim: 校啊招
|
||||
[stt->session] interim_transcript: 校啊招
|
||||
[stt] interim: 啊这种类
|
||||
[stt->session] interim_transcript: 啊这种类
|
||||
[stt] interim: 型我都是
|
||||
[stt->session] interim_transcript: 型我都是
|
||||
[stt] interim: 那种比较
|
||||
[stt->session] interim_transcript: 那种比较
|
||||
[stt] interim: 呃豪
|
||||
[stt->session] interim_transcript: 呃豪
|
||||
[stt] interim: 爽比
|
||||
[stt->session] interim_transcript: 爽比
|
||||
[stt] interim: 较开
|
||||
[stt->session] interim_transcript: 较开
|
||||
[stt] interim: 朗的那种
|
||||
[stt->session] interim_transcript: 朗的那种
|
||||
[stt] interim: 类型
|
||||
[stt->session] interim_transcript: 类型
|
||||
[stt] interim: 阳光大
|
||||
[stt->session] interim_transcript: 阳光大
|
||||
[stt] interim: 女孩
|
||||
[stt->session] interim_transcript: 女孩
|
||||
[stt] interim: 那种感
|
||||
[stt->session] interim_transcript: 那种感
|
||||
[stt] interim: 觉
|
||||
[stt->session] interim_transcript: 觉
|
||||
[stt] interim: 都给
|
||||
[stt->session] interim_transcript: 都给
|
||||
[stt] FINAL(merged): 烈火军校啊,朝阳啊这种类型我都是那种比较呃豪爽,比较开朗的那种类型,阳光大女孩那种感觉就
|
||||
[stt->session] final_transcript: 烈火军校啊,朝阳啊这种类型我都是那种比较呃豪爽,比较开朗的那种类型,阳光大女孩那
|
||||
[tts] first audio after 3.335s (原来你是那种阳光大女孩的类型啊,难怪感觉...)
|
||||
{"message": "livekit::rtc_engine::rtc_session:704:livekit::rtc_engine::rtc_session - publisher data channel '_reliable' closed unexpectedly", "level": "ERROR", "name": "livekit", "pid": 8885, "job_id": "AJ_dcfbVLNh9cxc", "room": "probe-room-2", "room_id": "RM_mNZagsczYXao", "timestamp": "2026-10-27T15:33:57.436181+00:00"}
|
||||
{"message": "livekit::rtc_engine::rtc_session:704:livekit::rtc_engine::rtc_session - publisher data channel '_lossy' closed unexpectedly", "level": "ERROR", "name": "livekit", "pid": 8885, "job_id": "AJ_dcfbVLNh9cxc", "room": "probe-room-2", "room_id": "RM_mNZagsczYXao", "timestamp": "2026-10-27T15:33:57.437201+00:00"}
|
||||
{"message": "livekit::rtc_engine::rtc_session:704:livekit::rtc_engine::rtc_session - publisher data channel '_data_track' closed unexpectedly", "level": "ERROR", "name": "livekit", "pid": 8885, "job_id": "AJ_dcfbVLNh9cxc", "room": "probe-room-2", "room_id": "RM_mNZagsczYXao", "timestamp": "2026-10-27T15:33:57.437449+00:00"}
|
||||
{"message": "process exiting", "level": "INFO", "name": "livekit.agents", "reason": "parent process shutdown", "pid": 8885, "job_id": "AJ_dcfbVLNh9cxc", "room": "probe-room-2", "room_id": "RM_mNZagsczYXao", "timestamp": "2026-10-27T15:33:59.447143+00:00"}
|
||||
[stt] interim: 怎么还
|
||||
[stt->session] interim_transcript: 怎么还
|
||||
[stt] interim: 有没事
|
||||
[stt->session] interim_transcript: 有没事
|
||||
[stt] interim: 的
|
||||
[stt->session] interim_transcript: 的
|
||||
[stt] FINAL(merged): 怎么还有没事的
|
||||
[stt->session] final_transcript: 怎么还有没事的
|
||||
[stt] interim: 是我不够
|
||||
[stt->session] interim_transcript: 是我不够
|
||||
[stt] interim: 努力
|
||||
[stt->session] interim_transcript: 努力
|
||||
[stt] FINAL(merged): 是我不够努力吗
|
||||
[stt->session] final_transcript: 是我不够努力吗
|
||||
[stt] interim: 盯着你看
|
||||
[stt->session] interim_transcript: 盯着你看
|
||||
[stt] interim: 怎么
|
||||
[stt->session] interim_transcript: 怎么
|
||||
[stt] FINAL(merged): 盯着你看怎么啦
|
||||
[stt->session] final_transcript: 盯着你看怎么啦
|
||||
[stt] interim: 难得
|
||||
[stt->session] interim_transcript: 难得
|
||||
[stt] interim: 看你这么
|
||||
[stt->session] interim_transcript: 看你这么
|
||||
[stt] interim: 有意思的
|
||||
[stt->session] interim_transcript: 有意思的
|
||||
[stt] interim: 样子
|
||||
[stt->session] interim_transcript: 样子
|
||||
{"message": "closing agent session due to participant disconnect (disable via `RoomInputOptions.close_on_disconnect=False`)", "level": "INFO", "name": "livekit.agents", "room": "cg-voice-qeghdnxehn", "participant": "user-gwhvezcz", "reason": "ROOM_DELETED", "pid": 8881, "job_id": "AJ_4vPjEVFaLPMq", "room_id": "RM_EMAorR7C2evE", "timestamp": "2026-10-27T15:34:12.027601+00:00"}
|
||||
{"message": "skipping user input, speech scheduling is paused", "level": "WARNING", "name": "livekit.agents", "lk.pii.user_input": "盯着你看怎么啦", "pid": 8881, "job_id": "AJ_4vPjEVFaLPMq", "room": "cg-voice-qeghdnxehn", "room_id": "RM_EMAorR7C2evE", "timestamp": "2026-10-27T15:34:12.040356+00:00"}
|
||||
{"message": "failed to send session event\nTraceback (most recent call last):\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/agents/voice/remote_session.py\", line 477, in _write_loop\n await self._transport.send_message(msg)\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/agents/voice/remote_session.py\", line 153, in send_message\n raise RuntimeError(\"room session transport is closed\")\nRuntimeError: room session transport is closed", "level": "WARNING", "name": "livekit.agents", "exc_info": "Traceback (most recent call last):\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/agents/voice/remote_session.py\", line 477, in _write_loop\n await self._transport.send_message(msg)\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/agents/voice/remote_session.py\", line 153, in send_message\n raise RuntimeError(\"room session transport is closed\")\nRuntimeError: room session transport is closed", "pid": 8881, "job_id": "AJ_4vPjEVFaLPMq", "room": "cg-voice-qeghdnxehn", "room_id": "RM_EMAorR7C2evE", "timestamp": "2026-10-27T15:34:12.042202+00:00"}
|
||||
[stt] FINAL(merged): 难得看你这么有意思的样子吗
|
||||
[stt->session] final_transcript: 难得看你这么有意思的样子吗
|
||||
{"message": "failed to send session event\nTraceback (most recent call last):\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/agents/voice/remote_session.py\", line 477, in _write_loop\n await self._transport.send_message(msg)\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/agents/voice/remote_session.py\", line 153, in send_message\n raise RuntimeError(\"room session transport is closed\")\nRuntimeError: room session transport is closed", "level": "WARNING", "name": "livekit.agents", "exc_info": "Traceback (most recent call last):\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/agents/voice/remote_session.py\", line 477, in _write_loop\n await self._transport.send_message(msg)\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/agents/voice/remote_session.py\", line 153, in send_message\n raise RuntimeError(\"room session transport is closed\")\nRuntimeError: room session transport is closed", "pid": 8881, "job_id": "AJ_4vPjEVFaLPMq", "room": "cg-voice-qeghdnxehn", "room_id": "RM_EMAorR7C2evE", "timestamp": "2026-10-27T15:34:12.890538+00:00"}
|
||||
{"message": "skipping user input, speech scheduling is paused", "level": "WARNING", "name": "livekit.agents", "lk.pii.user_input": "难得看你这么有意思的样子吗", "pid": 8881, "job_id": "AJ_4vPjEVFaLPMq", "room": "cg-voice-qeghdnxehn", "room_id": "RM_EMAorR7C2evE", "timestamp": "2026-10-27T15:34:12.891932+00:00"}
|
||||
{"message": "failed to send session event\nTraceback (most recent call last):\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/agents/voice/remote_session.py\", line 477, in _write_loop\n await self._transport.send_message(msg)\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/agents/voice/remote_session.py\", line 153, in send_message\n raise RuntimeError(\"room session transport is closed\")\nRuntimeError: room session transport is closed", "level": "WARNING", "name": "livekit.agents", "exc_info": "Traceback (most recent call last):\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/agents/voice/remote_session.py\", line 477, in _write_loop\n await self._transport.send_message(msg)\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/agents/voice/remote_session.py\", line 153, in send_message\n raise RuntimeError(\"room session transport is closed\")\nRuntimeError: room session transport is closed", "pid": 8881, "job_id": "AJ_4vPjEVFaLPMq", "room": "cg-voice-qeghdnxehn", "room_id": "RM_EMAorR7C2evE", "timestamp": "2026-10-27T15:34:12.892740+00:00"}
|
||||
{"message": "Task exception was never retrieved\nfuture: <Task finished name='Task-453' coro=<LocalParticipant.publish_data() done, defined at /opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/rtc/participant.py:315> exception=PublishDataError('engine: connection error: engine is closed')>\nTraceback (most recent call last):\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/rtc/participant.py\", line 359, in publish_data\n raise PublishDataError(cb.publish_data.error)\nlivekit.rtc.participant.PublishDataError: engine: connection error: engine is closed", "level": "ERROR", "name": "asyncio", "exc_info": "Traceback (most recent call last):\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/rtc/participant.py\", line 359, in publish_data\n raise PublishDataError(cb.publish_data.error)\nlivekit.rtc.participant.PublishDataError: engine: connection error: engine is closed", "pid": 8881, "job_id": "AJ_4vPjEVFaLPMq", "room": "cg-voice-qeghdnxehn", "room_id": "RM_EMAorR7C2evE", "timestamp": "2026-10-27T15:34:12.894879+00:00"}
|
||||
{"message": "process exiting", "level": "INFO", "name": "livekit.agents", "reason": "parent process shutdown", "pid": 8881, "job_id": "AJ_4vPjEVFaLPMq", "room": "cg-voice-qeghdnxehn", "room_id": "RM_EMAorR7C2evE", "timestamp": "2026-10-27T15:34:12.911612+00:00"}
|
||||
{"message": "received job request", "level": "INFO", "name": "livekit.agents", "job_id": "AJ_HpxBoFkqfBdm", "dispatch_id": "AD_QPVzQMzStdbx", "room": "cg-voice-ymtapbx42a", "room_id": "RM_5BfQDxZuTsu4", "agent_name": "cybergril-voice-agent", "resuming": false, "enable_recording": false, "pid": 8800, "timestamp": "2026-10-27T15:37:07.605078+00:00"}
|
||||
{"message": "initializing process", "level": "INFO", "name": "livekit.agents", "pid": 12418, "timestamp": "2026-10-27T15:37:07.631804+00:00"}
|
||||
{"message": "process initialized", "level": "INFO", "name": "livekit.agents", "pid": 12418, "elapsed_time": 0.11, "timestamp": "2026-10-27T15:37:07.743701+00:00"}
|
||||
Nvidia Decoder is supported.
|
||||
{"message": "adaptive interruption is disabled by default in production mode", "level": "INFO", "name": "livekit.agents", "pid": 10801, "job_id": "AJ_HpxBoFkqfBdm", "room": "cg-voice-ymtapbx42a", "room_id": "RM_5BfQDxZuTsu4", "timestamp": "2026-10-27T15:37:08.025546+00:00"}
|
||||
{"message": "failed to emit event conversation_item_added\nTraceback (most recent call last):\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/rtc/event_emitter.py\", line 70, in emit\n callback(*callback_args)\n File \"/opt/voice-agent-cybergril/cybergril/voice/worker.py\", line 193, in _on_item\n if ev.item.role == \"assistant\":\n ^^^^^^^^^^^^\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/pydantic/main.py\", line 1105, in __getattr__\n raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}')\nAttributeError: 'AgentHandoff' object has no attribute 'role'", "level": "ERROR", "name": "livekit", "exc_info": "Traceback (most recent call last):\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/rtc/event_emitter.py\", line 70, in emit\n callback(*callback_args)\n File \"/opt/voice-agent-cybergril/cybergril/voice/worker.py\", line 193, in _on_item\n if ev.item.role == \"assistant\":\n ^^^^^^^^^^^^\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/pydantic/main.py\", line 1105, in __getattr__\n raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}')\nAttributeError: 'AgentHandoff' object has no attribute 'role'", "pid": 10801, "job_id": "AJ_HpxBoFkqfBdm", "room": "cg-voice-ymtapbx42a", "room_id": "RM_5BfQDxZuTsu4", "timestamp": "2026-10-27T15:37:08.026426+00:00"}
|
||||
[cybergril-worker] session started (api=http://127.0.0.1:8360, voice=female_soft, agent_name=cybergril-voice-agent)
|
||||
{"message": "received job request", "level": "INFO", "name": "livekit.agents", "job_id": "AJ_MLg4JBtoku27", "dispatch_id": "AD_uMQVHwFMfKqf", "room": "cg-voice-5c4y64wxkl", "room_id": "RM_YDaqgLrwdfsB", "agent_name": "cybergril-voice-agent", "resuming": false, "enable_recording": false, "pid": 8800, "timestamp": "2026-10-27T15:37:11.445956+00:00"}
|
||||
{"message": "initializing process", "level": "INFO", "name": "livekit.agents", "pid": 12620, "timestamp": "2026-10-27T15:37:11.462186+00:00"}
|
||||
{"message": "process initialized", "level": "INFO", "name": "livekit.agents", "pid": 12620, "elapsed_time": 0.12, "timestamp": "2026-10-27T15:37:11.583631+00:00"}
|
||||
Nvidia Decoder is supported.
|
||||
{"message": "RoomIO linked to participant", "level": "INFO", "name": "livekit.agents", "lk.pii.participant_identity": "user-vdywshve", "lk.pii.room_name": "cg-voice-5c4y64wxkl", "pid": 11093, "job_id": "AJ_MLg4JBtoku27", "room": "cg-voice-5c4y64wxkl", "room_id": "RM_YDaqgLrwdfsB", "timestamp": "2026-10-27T15:37:11.840352+00:00"}
|
||||
{"message": "adaptive interruption is disabled by default in production mode", "level": "INFO", "name": "livekit.agents", "pid": 11093, "job_id": "AJ_MLg4JBtoku27", "room": "cg-voice-5c4y64wxkl", "room_id": "RM_YDaqgLrwdfsB", "timestamp": "2026-10-27T15:37:11.842501+00:00"}
|
||||
{"message": "failed to emit event conversation_item_added\nTraceback (most recent call last):\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/rtc/event_emitter.py\", line 70, in emit\n callback(*callback_args)\n File \"/opt/voice-agent-cybergril/cybergril/voice/worker.py\", line 193, in _on_item\n if ev.item.role == \"assistant\":\n ^^^^^^^^^^^^\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/pydantic/main.py\", line 1105, in __getattr__\n raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}')\nAttributeError: 'AgentHandoff' object has no attribute 'role'", "level": "ERROR", "name": "livekit", "exc_info": "Traceback (most recent call last):\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/rtc/event_emitter.py\", line 70, in emit\n callback(*callback_args)\n File \"/opt/voice-agent-cybergril/cybergril/voice/worker.py\", line 193, in _on_item\n if ev.item.role == \"assistant\":\n ^^^^^^^^^^^^\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/pydantic/main.py\", line 1105, in __getattr__\n raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}')\nAttributeError: 'AgentHandoff' object has no attribute 'role'", "pid": 11093, "job_id": "AJ_MLg4JBtoku27", "room": "cg-voice-5c4y64wxkl", "room_id": "RM_YDaqgLrwdfsB", "timestamp": "2026-10-27T15:37:11.844023+00:00"}
|
||||
[cybergril-worker] session started (api=http://127.0.0.1:8360, voice=female_soft, agent_name=cybergril-voice-agent)
|
||||
[stt] utterance open, frame sr=24000
|
||||
[stt] interim: 没
|
||||
[stt->session] interim_transcript: 没
|
||||
[stt] interim: 错
|
||||
[stt->session] interim_transcript: 错
|
||||
[stt] interim: 我就是个
|
||||
[stt->session] interim_transcript: 我就是个
|
||||
[stt] interim: 笨蛋
|
||||
[stt->session] interim_transcript: 笨蛋
|
||||
[stt] interim: 派大星
|
||||
[stt->session] interim_transcript: 派大星
|
||||
[stt] interim: 我们
|
||||
[stt->session] interim_transcript: 我们
|
||||
[stt] interim: 一起去
|
||||
[stt->session] interim_transcript: 一起去
|
||||
[stt] interim: 抓水母
|
||||
[stt->session] interim_transcript: 抓水母
|
||||
[stt] interim: 吧我
|
||||
[stt->session] interim_transcript: 吧我
|
||||
[stt] interim: 们一起度
|
||||
[stt->session] interim_transcript: 们一起度
|
||||
[stt] interim: 过快乐的
|
||||
[stt->session] interim_transcript: 过快乐的
|
||||
[stt] interim: 一天
|
||||
[stt->session] interim_transcript: 一天
|
||||
[stt] FINAL(merged): 没错,我就是个笨蛋派大星,我们一起去抓水母吧,我们一起度过快乐的一天
|
||||
[stt->session] final_transcript: 没错,我就是个笨蛋派大星,我们一起去抓水母吧,我们一起度过快乐的一天
|
||||
[tts] first audio after 3.909s (好呀,那我们这就出发去抓水母!不过我可不...)
|
||||
{"message": "livekit::rtc_engine::rtc_session:704:livekit::rtc_engine::rtc_session - publisher data channel '_reliable' closed unexpectedly", "level": "ERROR", "name": "livekit", "pid": 8883, "job_id": "AJ_FBBgf5Si2JYd", "room": "probe-room-3", "room_id": "RM_msdxb3QWFMYf", "timestamp": "2026-10-27T15:37:32.436074+00:00"}
|
||||
{"message": "livekit::rtc_engine::rtc_session:704:livekit::rtc_engine::rtc_session - publisher data channel '_lossy' closed unexpectedly", "level": "ERROR", "name": "livekit", "pid": 8883, "job_id": "AJ_FBBgf5Si2JYd", "room": "probe-room-3", "room_id": "RM_msdxb3QWFMYf", "timestamp": "2026-10-27T15:37:32.436405+00:00"}
|
||||
{"message": "livekit::rtc_engine::rtc_session:704:livekit::rtc_engine::rtc_session - publisher data channel '_data_track' closed unexpectedly", "level": "ERROR", "name": "livekit", "pid": 8883, "job_id": "AJ_FBBgf5Si2JYd", "room": "probe-room-3", "room_id": "RM_msdxb3QWFMYf", "timestamp": "2026-10-27T15:37:32.436558+00:00"}
|
||||
{"message": "process exiting", "level": "INFO", "name": "livekit.agents", "reason": "room disconnected", "pid": 8883, "job_id": "AJ_FBBgf5Si2JYd", "room": "probe-room-3", "room_id": "RM_msdxb3QWFMYf", "timestamp": "2026-10-27T15:37:34.449378+00:00"}
|
||||
[stt] interim: 天雷滚
|
||||
[stt->session] interim_transcript: 天雷滚
|
||||
[stt] interim: 滚我好
|
||||
[stt->session] interim_transcript: 滚我好
|
||||
[stt] interim: 怕怕
|
||||
[stt->session] interim_transcript: 怕怕
|
||||
[stt] interim: 劈
|
||||
[stt->session] interim_transcript: 劈
|
||||
[stt] interim: 的我浑
|
||||
[stt->session] interim_transcript: 的我浑
|
||||
[stt] interim: 身掉渣
|
||||
[stt->session] interim_transcript: 身掉渣
|
||||
[stt] interim: 渣突
|
||||
[stt->session] interim_transcript: 渣突
|
||||
[stt] interim: 破天
|
||||
[stt->session] interim_transcript: 破天
|
||||
[stt] interim: 劫我笑
|
||||
[stt->session] interim_transcript: 劫我笑
|
||||
[stt] interim: 哈哈
|
||||
[stt->session] interim_transcript: 哈哈
|
||||
[stt] interim: 逆
|
||||
[stt->session] interim_transcript: 逆
|
||||
[stt] interim: 天改命
|
||||
[stt->session] interim_transcript: 天改命
|
||||
[stt] interim: 我吹喇
|
||||
[stt->session] interim_transcript: 我吹喇
|
||||
[stt] interim: 叭滴
|
||||
[stt->session] interim_transcript: 叭滴
|
||||
[stt] interim: 答滴答
|
||||
[stt->session] interim_transcript: 答滴答
|
||||
[stt] interim: 滴滴
|
||||
[stt->session] interim_transcript: 滴滴
|
||||
[stt] FINAL(merged): 天雷滚滚,我好怕怕劈的我浑身掉渣渣,突破天劫,我笑哈哈逆天改命,我吹喇叭滴答滴答,滴滴答
|
||||
[stt->session] final_transcript: 天雷滚滚,我好怕怕劈的我浑身掉渣渣,突破天劫,我笑哈哈逆天改命,我吹喇叭滴答滴答
|
||||
[tts] first audio after 3.008s (哈哈,你唱得还挺有节奏感的!...)
|
||||
[stt] interim: 你是不是
|
||||
[stt->session] interim_transcript: 你是不是
|
||||
[stt] interim: 早就想
|
||||
[stt->session] interim_transcript: 早就想
|
||||
[stt] interim: 睡我
|
||||
[stt->session] interim_transcript: 睡我
|
||||
[stt] interim: 了
|
||||
[stt->session] interim_transcript: 了
|
||||
[stt] FINAL(merged): 你是不是早就想睡我了呀
|
||||
[stt->session] final_transcript: 你是不是早就想睡我了呀
|
||||
[tts] first audio after 3.304s (哈哈,你思维跳跃得太快了,我都跟不上。...)
|
||||
[stt] interim: 盯着你看
|
||||
[stt->session] interim_transcript: 盯着你看
|
||||
[stt] interim: 怎么啦
|
||||
[stt->session] interim_transcript: 怎么啦
|
||||
[stt] FINAL(merged): 盯着你看怎么啦
|
||||
[stt->session] final_transcript: 盯着你看怎么啦
|
||||
[tts] first audio after 2.405s (没...)
|
||||
{"message": "closing agent session due to participant disconnect (disable via `RoomInputOptions.close_on_disconnect=False`)", "level": "INFO", "name": "livekit.agents", "room": "cg-voice-5c4y64wxkl", "participant": "user-vdywshve", "reason": "ROOM_DELETED", "pid": 11093, "job_id": "AJ_MLg4JBtoku27", "room_id": "RM_YDaqgLrwdfsB", "timestamp": "2026-10-27T15:38:32.340079+00:00"}
|
||||
{"message": "livekit::rtc_engine::rtc_session:704:livekit::rtc_engine::rtc_session - publisher data channel '_reliable' closed unexpectedly", "level": "ERROR", "name": "livekit", "pid": 11093, "job_id": "AJ_MLg4JBtoku27", "room": "cg-voice-5c4y64wxkl", "room_id": "RM_YDaqgLrwdfsB", "timestamp": "2026-10-27T15:38:32.351146+00:00"}
|
||||
{"message": "livekit::rtc_engine::rtc_session:704:livekit::rtc_engine::rtc_session - publisher data channel '_lossy' closed unexpectedly", "level": "ERROR", "name": "livekit", "pid": 11093, "job_id": "AJ_MLg4JBtoku27", "room": "cg-voice-5c4y64wxkl", "room_id": "RM_YDaqgLrwdfsB", "timestamp": "2026-10-27T15:38:32.352194+00:00"}
|
||||
{"message": "livekit::rtc_engine::rtc_session:704:livekit::rtc_engine::rtc_session - publisher data channel '_data_track' closed unexpectedly", "level": "ERROR", "name": "livekit", "pid": 11093, "job_id": "AJ_MLg4JBtoku27", "room": "cg-voice-5c4y64wxkl", "room_id": "RM_YDaqgLrwdfsB", "timestamp": "2026-10-27T15:38:32.353282+00:00"}
|
||||
{"message": "process exiting", "level": "INFO", "name": "livekit.agents", "reason": "parent process shutdown", "pid": 11093, "job_id": "AJ_MLg4JBtoku27", "room": "cg-voice-5c4y64wxkl", "room_id": "RM_YDaqgLrwdfsB", "timestamp": "2026-10-27T15:38:34.358814+00:00"}
|
||||
{"message": "received job request", "level": "INFO", "name": "livekit.agents", "job_id": "AJ_a8uXggcKPamC", "dispatch_id": "AD_fxrSDuKoYdTr", "room": "cg-voice-6d0grxxwno", "room_id": "RM_bHsWETGZc5cQ", "agent_name": "cybergril-voice-agent", "resuming": false, "enable_recording": false, "pid": 8800, "timestamp": "2026-10-27T15:41:10.456804+00:00"}
|
||||
{"message": "initializing process", "level": "INFO", "name": "livekit.agents", "pid": 13261, "timestamp": "2026-10-27T15:41:10.492898+00:00"}
|
||||
{"message": "process initialized", "level": "INFO", "name": "livekit.agents", "pid": 13261, "elapsed_time": 0.12, "timestamp": "2026-10-27T15:41:10.613693+00:00"}
|
||||
Nvidia Decoder is supported.
|
||||
{"message": "adaptive interruption is disabled by default in production mode", "level": "INFO", "name": "livekit.agents", "pid": 11326, "job_id": "AJ_a8uXggcKPamC", "room": "cg-voice-6d0grxxwno", "room_id": "RM_bHsWETGZc5cQ", "timestamp": "2026-10-27T15:41:10.904892+00:00"}
|
||||
{"message": "failed to emit event conversation_item_added\nTraceback (most recent call last):\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/rtc/event_emitter.py\", line 70, in emit\n callback(*callback_args)\n File \"/opt/voice-agent-cybergril/cybergril/voice/worker.py\", line 193, in _on_item\n if ev.item.role == \"assistant\":\n ^^^^^^^^^^^^\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/pydantic/main.py\", line 1105, in __getattr__\n raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}')\nAttributeError: 'AgentHandoff' object has no attribute 'role'", "level": "ERROR", "name": "livekit", "exc_info": "Traceback (most recent call last):\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/rtc/event_emitter.py\", line 70, in emit\n callback(*callback_args)\n File \"/opt/voice-agent-cybergril/cybergril/voice/worker.py\", line 193, in _on_item\n if ev.item.role == \"assistant\":\n ^^^^^^^^^^^^\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/pydantic/main.py\", line 1105, in __getattr__\n raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}')\nAttributeError: 'AgentHandoff' object has no attribute 'role'", "pid": 11326, "job_id": "AJ_a8uXggcKPamC", "room": "cg-voice-6d0grxxwno", "room_id": "RM_bHsWETGZc5cQ", "timestamp": "2026-10-27T15:41:10.905825+00:00"}
|
||||
[cybergril-worker] session started (api=http://127.0.0.1:8360, voice=female_soft, agent_name=cybergril-voice-agent)
|
||||
{"message": "livekit::rtc_engine::rtc_session:704:livekit::rtc_engine::rtc_session - publisher data channel '_reliable' closed unexpectedly", "level": "ERROR", "name": "livekit", "pid": 11326, "job_id": "AJ_a8uXggcKPamC", "room": "cg-voice-6d0grxxwno", "room_id": "RM_bHsWETGZc5cQ", "timestamp": "2026-10-27T15:41:30.437268+00:00"}
|
||||
{"message": "livekit::rtc_engine::rtc_session:704:livekit::rtc_engine::rtc_session - publisher data channel '_lossy' closed unexpectedly", "level": "ERROR", "name": "livekit", "pid": 11326, "job_id": "AJ_a8uXggcKPamC", "room": "cg-voice-6d0grxxwno", "room_id": "RM_bHsWETGZc5cQ", "timestamp": "2026-10-27T15:41:30.437449+00:00"}
|
||||
{"message": "livekit::rtc_engine::rtc_session:704:livekit::rtc_engine::rtc_session - publisher data channel '_data_track' closed unexpectedly", "level": "ERROR", "name": "livekit", "pid": 11326, "job_id": "AJ_a8uXggcKPamC", "room": "cg-voice-6d0grxxwno", "room_id": "RM_bHsWETGZc5cQ", "timestamp": "2026-10-27T15:41:30.437534+00:00"}
|
||||
{"message": "received job request", "level": "INFO", "name": "livekit.agents", "job_id": "AJ_sfYen6Augi9u", "dispatch_id": "AD_UmNB9yQbmDEK", "room": "cg-voice-oleganioz7", "room_id": "RM_anqqGcUZrCbe", "agent_name": "cybergril-voice-agent", "resuming": false, "enable_recording": false, "pid": 8800, "timestamp": "2026-10-27T15:41:30.448381+00:00"}
|
||||
{"message": "initializing process", "level": "INFO", "name": "livekit.agents", "pid": 13614, "timestamp": "2026-10-27T15:41:30.549122+00:00"}
|
||||
{"message": "process initialized", "level": "INFO", "name": "livekit.agents", "pid": 13614, "elapsed_time": 0.12, "timestamp": "2026-10-27T15:41:30.671152+00:00"}
|
||||
Nvidia Decoder is supported.
|
||||
{"message": "RoomIO linked to participant", "level": "INFO", "name": "livekit.agents", "lk.pii.participant_identity": "user-uqfyuhnt", "lk.pii.room_name": "cg-voice-oleganioz7", "pid": 11830, "job_id": "AJ_sfYen6Augi9u", "room": "cg-voice-oleganioz7", "room_id": "RM_anqqGcUZrCbe", "timestamp": "2026-10-27T15:41:30.841632+00:00"}
|
||||
{"message": "adaptive interruption is disabled by default in production mode", "level": "INFO", "name": "livekit.agents", "pid": 11830, "job_id": "AJ_sfYen6Augi9u", "room": "cg-voice-oleganioz7", "room_id": "RM_anqqGcUZrCbe", "timestamp": "2026-10-27T15:41:30.843597+00:00"}
|
||||
{"message": "failed to emit event conversation_item_added\nTraceback (most recent call last):\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/rtc/event_emitter.py\", line 70, in emit\n callback(*callback_args)\n File \"/opt/voice-agent-cybergril/cybergril/voice/worker.py\", line 193, in _on_item\n if ev.item.role == \"assistant\":\n ^^^^^^^^^^^^\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/pydantic/main.py\", line 1105, in __getattr__\n raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}')\nAttributeError: 'AgentHandoff' object has no attribute 'role'", "level": "ERROR", "name": "livekit", "exc_info": "Traceback (most recent call last):\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/livekit/rtc/event_emitter.py\", line 70, in emit\n callback(*callback_args)\n File \"/opt/voice-agent-cybergril/cybergril/voice/worker.py\", line 193, in _on_item\n if ev.item.role == \"assistant\":\n ^^^^^^^^^^^^\n File \"/opt/voice-agent/agent/venv/lib/python3.12/site-packages/pydantic/main.py\", line 1105, in __getattr__\n raise AttributeError(f'{type(self).__name__!r} object has no attribute {item!r}')\nAttributeError: 'AgentHandoff' object has no attribute 'role'", "pid": 11830, "job_id": "AJ_sfYen6Augi9u", "room": "cg-voice-oleganioz7", "room_id": "RM_anqqGcUZrCbe", "timestamp": "2026-10-27T15:41:30.844442+00:00"}
|
||||
[cybergril-worker] session started (api=http://127.0.0.1:8360, voice=female_soft, agent_name=cybergril-voice-agent)
|
||||
[stt] utterance open, frame sr=24000
|
||||
[stt] interim: 师
|
||||
[stt->session] interim_transcript: 师
|
||||
[stt] interim: 傅
|
||||
[stt->session] interim_transcript: 傅
|
||||
{"message": "process exiting", "level": "INFO", "name": "livekit.agents", "reason": "parent process shutdown", "pid": 11326, "job_id": "AJ_a8uXggcKPamC", "room": "cg-voice-6d0grxxwno", "room_id": "RM_bHsWETGZc5cQ", "timestamp": "2026-10-27T15:41:32.444706+00:00"}
|
||||
[stt] interim: 哎这
|
||||
[stt->session] interim_transcript: 哎这
|
||||
[stt] interim: 取经
|
||||
[stt->session] interim_transcript: 取经
|
||||
[stt] interim: 路比
|
||||
[stt->session] interim_transcript: 路比
|
||||
[stt] interim: 高老
|
||||
[stt->session] interim_transcript: 高老
|
||||
[stt] interim: 庄种
|
||||
[stt->session] interim_transcript: 庄种
|
||||
[stt] interim: 地还
|
||||
[stt->session] interim_transcript: 地还
|
||||
[stt] interim: 苦俺
|
||||
[stt->session] interim_transcript: 苦俺
|
||||
[stt] interim: 老中
|
||||
[stt->session] interim_transcript: 老中
|
||||
[stt] interim: 饿的能
|
||||
[stt->session] interim_transcript: 饿的能
|
||||
[stt] interim: 吞下
|
||||
[stt->session] interim_transcript: 吞下
|
||||
[stt] interim: 石龙
|
||||
[stt->session] interim_transcript: 石龙
|
||||
[stt] interim: 素包
|
||||
[stt->session] interim_transcript: 素包
|
||||
[stt] interim: 子
|
||||
[stt->session] interim_transcript: 子
|
||||
[stt] interim: 猴哥
|
||||
[stt->session] interim_transcript: 猴哥
|
||||
[stt] interim: 你筋
|
||||
[stt->session] interim_transcript: 你筋
|
||||
[stt] interim: 斗云
|
||||
[stt->session] interim_transcript: 斗云
|
||||
[stt] interim: 快
|
||||
[stt->session] interim_transcript: 快
|
||||
[stt] interim: 要不
|
||||
[stt->session] interim_transcript: 要不
|
||||
[stt] interim: 先
|
||||
[stt->session] interim_transcript: 先
|
||||
[stt] interim: 去画个
|
||||
[stt->session] interim_transcript: 去画个
|
||||
[stt] FINAL(merged): 师傅,哎,这取经路比高,老庄种地还苦,俺老猪饿的能吞下石龙素包子,猴哥,你筋斗云块,要不先去化个缘
|
||||
[stt->session] final_transcript: 师傅,哎,这取经路比高,老庄种地还苦,俺老猪饿的能吞下石龙素包子,猴哥,你筋斗云
|
||||
[tts] first audio after 2.480s (师傅,...)
|
||||
{"message": "livekit::rtc_engine::rtc_session:704:livekit::rtc_engine::rtc_session - publisher data channel '_reliable' closed unexpectedly", "level": "ERROR", "name": "livekit", "pid": 10801, "job_id": "AJ_HpxBoFkqfBdm", "room": "cg-voice-ymtapbx42a", "room_id": "RM_5BfQDxZuTsu4", "timestamp": "2026-10-27T15:42:07.442254+00:00"}
|
||||
{"message": "livekit::rtc_engine::rtc_session:704:livekit::rtc_engine::rtc_session - publisher data channel '_lossy' closed unexpectedly", "level": "ERROR", "name": "livekit", "pid": 10801, "job_id": "AJ_HpxBoFkqfBdm", "room": "cg-voice-ymtapbx42a", "room_id": "RM_5BfQDxZuTsu4", "timestamp": "2026-10-27T15:42:07.442585+00:00"}
|
||||
{"message": "livekit::rtc_engine::rtc_session:704:livekit::rtc_engine::rtc_session - publisher data channel '_data_track' closed unexpectedly", "level": "ERROR", "name": "livekit", "pid": 10801, "job_id": "AJ_HpxBoFkqfBdm", "room": "cg-voice-ymtapbx42a", "room_id": "RM_5BfQDxZuTsu4", "timestamp": "2026-10-27T15:42:07.442726+00:00"}
|
||||
{"message": "process exiting", "level": "INFO", "name": "livekit.agents", "reason": "parent process shutdown", "pid": 10801, "job_id": "AJ_HpxBoFkqfBdm", "room": "cg-voice-ymtapbx42a", "room_id": "RM_5BfQDxZuTsu4", "timestamp": "2026-10-27T15:42:09.450806+00:00"}
|
||||
[stt] interim: 俺老
|
||||
[stt->session] interim_transcript: 俺老
|
||||
[stt] interim: 孙来
|
||||
[stt->session] interim_transcript: 孙来
|
||||
[stt] interim: 也俺
|
||||
[stt->session] interim_transcript: 也俺
|
||||
[stt] interim: 乃五百
|
||||
[stt->session] interim_transcript: 乃五百
|
||||
[stt] interim: 年前
|
||||
[stt->session] interim_transcript: 年前
|
||||
[stt] interim: 大闹
|
||||
[stt->session] interim_transcript: 大闹
|
||||
[stt] interim: 天宫的
|
||||
[stt->session] interim_transcript: 天宫的
|
||||
[stt] interim: 齐天
|
||||
[stt->session] interim_transcript: 齐天
|
||||
[stt] interim: 霸圣
|
||||
[stt->session] interim_transcript: 霸圣
|
||||
[stt] interim: 孙悟
|
||||
[stt->session] interim_transcript: 孙悟
|
||||
[stt] interim: 空这
|
||||
[stt->session] interim_transcript: 空这
|
||||
[stt] interim: 里山
|
||||
[stt->session] interim_transcript: 里山
|
||||
[stt] interim: 势险
|
||||
[stt->session] interim_transcript: 势险
|
||||
[stt] interim: 峻
|
||||
[stt->session] interim_transcript: 峻
|
||||
[stt] interim: 只怕藏
|
||||
[stt->session] interim_transcript: 只怕藏
|
||||
[stt] interim: 有妖
|
||||
[stt->session] interim_transcript: 有妖
|
||||
[stt] interim: 精妖
|
||||
[stt->session] interim_transcript: 精妖
|
||||
[stt] interim: 怪
|
||||
[stt->session] interim_transcript: 怪
|
||||
[stt] interim: 哪里
|
||||
[stt->session] interim_transcript: 哪里
|
||||
[stt] interim: 逃
|
||||
[stt->session] interim_transcript: 逃
|
||||
[stt] interim: 吃完老
|
||||
[stt->session] interim_transcript: 吃完老
|
||||
[stt] interim: 我所
|
||||
[stt->session] interim_transcript: 我所
|
||||
[stt] interim: 一
|
||||
[stt->session] interim_transcript: 一
|
||||
[stt] FINAL(merged): 俺老孙来也,俺乃500年前大闹天宫的齐天大圣孙悟空,这里山势险峻,只怕藏有妖精妖怪,哪里逃吃?俺老孙吧
|
||||
[stt->session] final_transcript: 俺老孙来也,俺乃500年前大闹天宫的齐天大圣孙悟空,这里山势险峻,只怕藏有妖精妖
|
||||
[tts] first audio after 2.608s (好...)
|
||||
[stt] interim: 没
|
||||
[stt->session] interim_transcript: 没
|
||||
[stt] interim: 错我
|
||||
[stt->session] interim_transcript: 错我
|
||||
[stt] interim: 就是个笨
|
||||
[stt->session] interim_transcript: 就是个笨
|
||||
[stt] interim: 蛋
|
||||
[stt->session] interim_transcript: 蛋
|
||||
[stt] interim: 派大
|
||||
[stt->session] interim_transcript: 派大
|
||||
[stt] interim: 星我们一
|
||||
[stt->session] interim_transcript: 星我们一
|
||||
[stt] interim: 起去抓
|
||||
[stt->session] interim_transcript: 起去抓
|
||||
[stt] interim: 水母
|
||||
[stt->session] interim_transcript: 水母
|
||||
[stt] interim: 吧我们
|
||||
[stt->session] interim_transcript: 吧我们
|
||||
[stt] interim: 一起度
|
||||
[stt->session] interim_transcript: 一起度
|
||||
[stt] interim: 过快乐的一
|
||||
[stt->session] interim_transcript: 过快乐的一
|
||||
[stt] FINAL(merged): 没错,我就是个笨蛋派大星,我们一起去抓水母吧,我们一起度过快乐的一天
|
||||
[stt->session] final_transcript: 没错,我就是个笨蛋派大星,我们一起去抓水母吧,我们一起度过快乐的一天
|
||||
[tts] first audio after 2.300s (好...)
|
||||
[stt] interim: 你是不是
|
||||
[stt->session] interim_transcript: 你是不是
|
||||
[stt] interim: 早就想
|
||||
[stt->session] interim_transcript: 早就想
|
||||
[stt] interim: 睡我
|
||||
[stt->session] interim_transcript: 睡我
|
||||
[stt] interim: 了
|
||||
[stt->session] interim_transcript: 了
|
||||
[stt] FINAL(merged): 你是不是早就想睡我了呀
|
||||
[stt->session] final_transcript: 你是不是早就想睡我了呀
|
||||
{"message": "failed to generate LLM completion: chat stream ended without final or error (caused by ChatApiConnectionError: chat stream ended without final or error), retrying in 0.1s", "level": "WARNING", "name": "livekit.agents", "llm": "cybergril.voice.llm_chat_api.CyberGrillLLM", "attempt": 1, "pid": 11830, "job_id": "AJ_sfYen6Augi9u", "room": "cg-voice-oleganioz7", "room_id": "RM_anqqGcUZrCbe", "timestamp": "2026-10-27T15:46:34.451048+00:00"}
|
||||
[tts] first audio after 3.847s (Considering the limi...)
|
||||
[tts] first audio after 2.284s (</think>...)
|
||||
{"message": "closing agent session due to participant disconnect (disable via `RoomInputOptions.close_on_disconnect=False`)", "level": "INFO", "name": "livekit.agents", "room": "cg-voice-oleganioz7", "participant": "user-uqfyuhnt", "reason": "CLIENT_INITIATED", "pid": 11830, "job_id": "AJ_sfYen6Augi9u", "room_id": "RM_anqqGcUZrCbe", "timestamp": "2026-10-27T15:46:46.019622+00:00"}
|
||||
{"message": "process exiting", "level": "INFO", "name": "livekit.agents", "reason": "parent process shutdown", "pid": 11830, "job_id": "AJ_sfYen6Augi9u", "room": "cg-voice-oleganioz7", "room_id": "RM_anqqGcUZrCbe", "timestamp": "2026-10-27T15:47:06.441875+00:00"}
|
||||
{"message": "livekit_ffi::server:279:livekit_ffi::server - Attempted to drop unknown FFI handle: 16", "level": "WARNING", "name": "livekit", "pid": 11830, "job_id": "AJ_sfYen6Augi9u", "room": "cg-voice-oleganioz7", "room_id": "RM_anqqGcUZrCbe", "timestamp": "2026-10-27T15:47:06.446226+00:00"}
|
||||
{"message": "draining worker", "level": "INFO", "name": "livekit.agents", "id": "AW_LGViCVagSNNu", "timeout": 3600, "pid": 8800, "timestamp": "2026-10-27T15:58:10.576647+00:00"}
|
||||
{"message": "shutting down worker", "level": "INFO", "name": "livekit.agents", "id": "AW_LGViCVagSNNu", "pid": 8800, "timestamp": "2026-10-27T15:58:10.577287+00:00"}
|
||||
@@ -0,0 +1,215 @@
|
||||
{
|
||||
"head": "HEL-894 close ownership under cancellation",
|
||||
"real_llm_requests": 0,
|
||||
"real_embeddings": 0,
|
||||
"boundary": "deterministic 512 vectors, non-loopback forbidden",
|
||||
"protocol": "drain-phase cancel re-arms; finish-phase cancel keeps markers, refuses ticks, lands the layer-owned close exactly once; lock waiters never touch the owner's state",
|
||||
"checks": [
|
||||
{
|
||||
"name": "F1 cancelled caller does not return before its close lands",
|
||||
"ok": true,
|
||||
"detail": ""
|
||||
},
|
||||
{
|
||||
"name": "F1 markers stay: closing set, not yet closed, client untouched",
|
||||
"ok": true,
|
||||
"detail": "{\"closing\": true, \"closed\": false, \"client_usable\": true}"
|
||||
},
|
||||
{
|
||||
"name": "F1 tick during closing claims nothing and sends nothing",
|
||||
"ok": true,
|
||||
"detail": "{\"gateway_arrived\": false, \"gateway_posts\": 0, \"llm_used\": 0, \"batch\": {\"state\": \"queued\", \"reason\": null, \"owner\": null, \"attempts\": 0, \"entry_ids\": null}}"
|
||||
},
|
||||
{
|
||||
"name": "F1 layer-owned close lands exactly once, no live workers",
|
||||
"ok": true,
|
||||
"detail": "{\"closed\": true, \"client_usable\": false, \"live_workers\": 0, \"close_calls\": 1, \"closing_still_set\": true, \"batch\": {\"state\": \"queued\", \"reason\": null, \"owner\": null, \"attempts\": 0, \"entry_ids\": null}}"
|
||||
},
|
||||
{
|
||||
"name": "F1 no late error",
|
||||
"ok": true,
|
||||
"detail": "None"
|
||||
},
|
||||
{
|
||||
"name": "F1 reopened batch intact and unbilled",
|
||||
"ok": true,
|
||||
"detail": "{\"state\": \"queued\", \"reason\": null, \"owner\": null, \"attempts\": 0, \"entry_ids\": null, \"row_done\": 0, \"llm_used\": 0}"
|
||||
},
|
||||
{
|
||||
"name": "F2 cancelled caller does not return before its close lands",
|
||||
"ok": true,
|
||||
"detail": ""
|
||||
},
|
||||
{
|
||||
"name": "F2 markers stay: closing set, not yet closed, client untouched",
|
||||
"ok": true,
|
||||
"detail": "{\"closing\": true, \"closed\": false, \"client_usable\": true}"
|
||||
},
|
||||
{
|
||||
"name": "F2 tick during closing claims nothing and sends nothing",
|
||||
"ok": true,
|
||||
"detail": "{\"gateway_arrived\": false, \"gateway_posts\": 0, \"llm_used\": 0, \"batch\": {\"state\": \"queued\", \"reason\": null, \"owner\": null, \"attempts\": 0, \"entry_ids\": null}}"
|
||||
},
|
||||
{
|
||||
"name": "F2 layer-owned close lands exactly once, no live workers",
|
||||
"ok": true,
|
||||
"detail": "{\"closed\": true, \"client_usable\": false, \"live_workers\": 0, \"close_calls\": 1, \"closing_still_set\": true, \"batch\": {\"state\": \"queued\", \"reason\": null, \"owner\": null, \"attempts\": 0, \"entry_ids\": null}}"
|
||||
},
|
||||
{
|
||||
"name": "F2 no late error",
|
||||
"ok": true,
|
||||
"detail": "None"
|
||||
},
|
||||
{
|
||||
"name": "F2 reopened batch intact and unbilled",
|
||||
"ok": true,
|
||||
"detail": "{\"state\": \"queued\", \"reason\": null, \"owner\": null, \"attempts\": 0, \"entry_ids\": null, \"row_done\": 0, \"llm_used\": 0}"
|
||||
},
|
||||
{
|
||||
"name": "W owner close still pending, waiter cancel keeps the signal",
|
||||
"ok": true,
|
||||
"detail": "{\"active_close_pending\": true, \"signal_after_waiter_cancel\": true}"
|
||||
},
|
||||
{
|
||||
"name": "W new batch refused during the owner's close",
|
||||
"ok": true,
|
||||
"detail": "{\"state\": \"queued\", \"reason\": null, \"owner\": null, \"attempts\": 0, \"entry_ids\": null}"
|
||||
},
|
||||
{
|
||||
"name": "W original batch still actively owned while blocked",
|
||||
"ok": true,
|
||||
"detail": "{\"state\": \"pending\", \"reason\": null, \"owner\": \"a6173b4a79a84dbd6378281c17b23127\", \"attempts\": 1, \"entry_ids\": null}"
|
||||
},
|
||||
{
|
||||
"name": "W original worker completes, one close, new batch untouched",
|
||||
"ok": true,
|
||||
"detail": "{\"original_batch\": {\"state\": \"done\", \"reason\": null, \"owner\": null, \"attempts\": 1, \"entry_ids\": \"[\\\"494b27cf-6e99-4e9a-ad17-bc4c9d2f42ec\\\"]\"}, \"new_batch_still\": {\"state\": \"queued\", \"reason\": null, \"owner\": null, \"attempts\": 0, \"entry_ids\": null}, \"row_done\": 1, \"gateway_posts_after_release\": 1, \"client_closed\": true}"
|
||||
}
|
||||
],
|
||||
"finish_cancel_sdk_only": {
|
||||
"caller_done_after_cancel": false,
|
||||
"after_cancellation": {
|
||||
"closing": true,
|
||||
"closed": false,
|
||||
"client_usable": true
|
||||
},
|
||||
"tick_during_closing": {
|
||||
"gateway_arrived": false,
|
||||
"gateway_posts": 0,
|
||||
"llm_used": 0,
|
||||
"batch": {
|
||||
"state": "queued",
|
||||
"reason": null,
|
||||
"owner": null,
|
||||
"attempts": 0,
|
||||
"entry_ids": null
|
||||
}
|
||||
},
|
||||
"finish_landed": {
|
||||
"closed": true,
|
||||
"client_usable": false,
|
||||
"live_workers": 0,
|
||||
"close_calls": 1,
|
||||
"closing_still_set": true,
|
||||
"batch": {
|
||||
"state": "queued",
|
||||
"reason": null,
|
||||
"owner": null,
|
||||
"attempts": 0,
|
||||
"entry_ids": null
|
||||
}
|
||||
},
|
||||
"late_worker_error": null,
|
||||
"persisted": {
|
||||
"state": "queued",
|
||||
"reason": null,
|
||||
"owner": null,
|
||||
"attempts": 0,
|
||||
"entry_ids": null,
|
||||
"row_done": 0,
|
||||
"llm_used": 0
|
||||
}
|
||||
},
|
||||
"finish_cancel_then_store_close": {
|
||||
"caller_done_after_cancel": false,
|
||||
"after_cancellation": {
|
||||
"closing": true,
|
||||
"closed": false,
|
||||
"client_usable": true
|
||||
},
|
||||
"tick_during_closing": {
|
||||
"gateway_arrived": false,
|
||||
"gateway_posts": 0,
|
||||
"llm_used": 0,
|
||||
"batch": {
|
||||
"state": "queued",
|
||||
"reason": null,
|
||||
"owner": null,
|
||||
"attempts": 0,
|
||||
"entry_ids": null
|
||||
}
|
||||
},
|
||||
"finish_landed": {
|
||||
"closed": true,
|
||||
"client_usable": false,
|
||||
"live_workers": 0,
|
||||
"close_calls": 1,
|
||||
"closing_still_set": true,
|
||||
"batch": {
|
||||
"state": "queued",
|
||||
"reason": null,
|
||||
"owner": null,
|
||||
"attempts": 0,
|
||||
"entry_ids": null
|
||||
}
|
||||
},
|
||||
"late_worker_error": null,
|
||||
"persisted": {
|
||||
"state": "queued",
|
||||
"reason": null,
|
||||
"owner": null,
|
||||
"attempts": 0,
|
||||
"entry_ids": null,
|
||||
"row_done": 0,
|
||||
"llm_used": 0
|
||||
}
|
||||
},
|
||||
"waiter_cancel": {
|
||||
"active_close_pending": true,
|
||||
"signal_after_waiter_cancel": true,
|
||||
"new_batch_during_closing": {
|
||||
"state": "queued",
|
||||
"reason": null,
|
||||
"owner": null,
|
||||
"attempts": 0,
|
||||
"entry_ids": null
|
||||
},
|
||||
"original_batch_while_blocked": {
|
||||
"state": "pending",
|
||||
"reason": null,
|
||||
"owner": "a6173b4a79a84dbd6378281c17b23127",
|
||||
"attempts": 1,
|
||||
"entry_ids": null
|
||||
},
|
||||
"after_release": {
|
||||
"original_batch": {
|
||||
"state": "done",
|
||||
"reason": null,
|
||||
"owner": null,
|
||||
"attempts": 1,
|
||||
"entry_ids": "[\"494b27cf-6e99-4e9a-ad17-bc4c9d2f42ec\"]"
|
||||
},
|
||||
"new_batch_still": {
|
||||
"state": "queued",
|
||||
"reason": null,
|
||||
"owner": null,
|
||||
"attempts": 0,
|
||||
"entry_ids": null
|
||||
},
|
||||
"row_done": 1,
|
||||
"gateway_posts_after_release": 1,
|
||||
"client_closed": true
|
||||
}
|
||||
},
|
||||
"failures": []
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
{
|
||||
"head": "HEL-886 inflight lifecycle",
|
||||
"real_llm_requests": 0,
|
||||
"real_embeddings": 0,
|
||||
"boundary": "deterministic 512 vectors, non-loopback forbidden",
|
||||
"checks": [
|
||||
{
|
||||
"name": "L1_cancel_single_send_and_full_record",
|
||||
"ok": true,
|
||||
"detail": "arrived=1 concurrent=1 http_total=1 points=1 batch_live={'state': 'pending', 'owner': '9a6afb62871305fe6c7a056acf0b8797'} batch_concurrent=pending final={'state': 'done', 'reason': None, 'entry_ids': '[\"9838ab55-15ab-4872-b7cd-1ba91faea2d7\"]'} row_done=1"
|
||||
},
|
||||
{
|
||||
"name": "L2_lease_single_send_and_full_record",
|
||||
"ok": true,
|
||||
"detail": "arrived=1 concurrent=1 http_total=1 points=1 batch_live={'state': 'pending', 'owner': '8f42725681bcfda7043797c128eb0750'} batch_concurrent=pending final={'state': 'done', 'reason': None, 'entry_ids': '[\"e71ba931-650f-40a3-b571-5945829f6f7c\"]'} row_done=1"
|
||||
},
|
||||
{
|
||||
"name": "L3_shutdown_drains_live_worker_before_close",
|
||||
"ok": true,
|
||||
"detail": "arrived=1 waited=0.25s row_done_at=2000000 batch={'state': 'done', 'finished_at': 2000000}"
|
||||
},
|
||||
{
|
||||
"name": "L4a_all_done_finalizes_without_new_budget",
|
||||
"ok": true,
|
||||
"detail": "before={'state': 'done', 'entry_ids': '[\"80c8cb6b-e437-478c-a3fb-46d386ac9a07\"]'} after={'state': 'done', 'reason': None, 'entry_ids': '[\"80c8cb6b-e437-478c-a3fb-46d386ac9a07\"]'} http=1 llm_used=1"
|
||||
},
|
||||
{
|
||||
"name": "L4b_partial_keeps_the_hard_gate",
|
||||
"ok": true,
|
||||
"detail": "after={'state': 'queued', 'reason': 'semantic_llm_budget_exhausted'} http=0"
|
||||
},
|
||||
{
|
||||
"name": "L5_dead_owner_lease_still_recovers",
|
||||
"ok": true,
|
||||
"detail": "recovered={'state': 'failed', 'reason': 'lease_expired'} after={'state': 'done'} http=2"
|
||||
}
|
||||
],
|
||||
"gateway_requests_total": 7,
|
||||
"failures": []
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
{
|
||||
"started": "2026-10-26T19:35:46Z",
|
||||
"embedding_boundary": "deterministic 512-dimensional vectors installed before TextEmbedding construction; no model loaded; zero real embeddings",
|
||||
"external_network": "socket.connect rejects all non-loopback hosts",
|
||||
"install": {
|
||||
"python": "3.10.12",
|
||||
"mem0ai": "2.2.1",
|
||||
"qdrant-client": "1.20.0",
|
||||
"fastembed": "0.9.1",
|
||||
"mem0_path": "/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-857-2cf6dc7dfc87/workdir/hel857-venv/lib/python3.10/site-packages/mem0",
|
||||
"module_sha256": {
|
||||
"memory/main.py": "f329ca4a17af1fbefb32ac10d4cc7ae7ddbdb7435a87eb74c30915cff98b8b7c",
|
||||
"memory/storage.py": "5f5ecdadd2b260fd14f36a0f338336eb760275465dd1056a99a47e1ef07702bd",
|
||||
"embeddings/fastembed.py": "3ec2ae87df5d0bebedb8b5471366c3412975847458499f66097f7b8c9ac8c9b8",
|
||||
"llms/openai.py": "37e6d3c22b55df0731740f4e0868b95bd480ce44363227fe53461db328c5f67e",
|
||||
"vector_stores/qdrant.py": "da570579d5cad69e6f123fdfe32b725235a25604e70047666bec763ba6e2bf43"
|
||||
},
|
||||
"source_tarball_sha256": "9dcef9303ebcec116eec6739f01b8b35bd24459de6a569686b4d19b9412dda23"
|
||||
},
|
||||
"adapter_has_llm_guard": true,
|
||||
"checks": [
|
||||
{
|
||||
"name": "C1_construct",
|
||||
"ok": true,
|
||||
"detail": "client_path=sdk-vector-store-client"
|
||||
},
|
||||
{
|
||||
"name": "C2_add_anchor_payload",
|
||||
"ok": true,
|
||||
"detail": "created=True payload_keys=['created_at', 'data', 'hash', 'input_sha256', 'src_group', 'text_lemmatized', 'turn_ids', 'turn_roles']"
|
||||
},
|
||||
{
|
||||
"name": "C2_add_user_scope",
|
||||
"ok": true,
|
||||
"detail": "user_id present in stored payload"
|
||||
},
|
||||
{
|
||||
"name": "C2_add_ledger_shape",
|
||||
"ok": true,
|
||||
"detail": "embed_items=3 llm_calls=1"
|
||||
},
|
||||
{
|
||||
"name": "C3_extraction_input_set",
|
||||
"ok": true,
|
||||
"detail": "old_memory=True new_row=True history_carry=True"
|
||||
},
|
||||
{
|
||||
"name": "C3b_unshared_canary_never_outbound",
|
||||
"ok": true,
|
||||
"detail": "queued_public_batches=2 leaked=False anchor_taint=False"
|
||||
},
|
||||
{
|
||||
"name": "C4_search_filters",
|
||||
"ok": true,
|
||||
"detail": "hits=3"
|
||||
},
|
||||
{
|
||||
"name": "C4_search_single_debit",
|
||||
"ok": true,
|
||||
"detail": "embed_delta=1 (pre-fix=2)"
|
||||
},
|
||||
{
|
||||
"name": "C6_concurrency_cap",
|
||||
"ok": true,
|
||||
"detail": "outcomes=['ok', 'refused'] used=3 cap=3"
|
||||
},
|
||||
{
|
||||
"name": "C7_reopen_after_close",
|
||||
"ok": true,
|
||||
"detail": "hits_after_reopen=3"
|
||||
},
|
||||
{
|
||||
"name": "C5_embed_zero_refuses",
|
||||
"ok": true,
|
||||
"detail": "err=semantic_embed_budget_not_approved llm_sent=0"
|
||||
},
|
||||
{
|
||||
"name": "C5_llm_zero_refuses",
|
||||
"ok": true,
|
||||
"detail": "err=semantic_llm_budget_not_approved llm_sent=0"
|
||||
}
|
||||
],
|
||||
"embed_rows_after_first_add": [
|
||||
{
|
||||
"kind": "authority_prefix",
|
||||
"items": 0,
|
||||
"note": "authority:synthetic-verify-prefix"
|
||||
},
|
||||
{
|
||||
"kind": "dense",
|
||||
"items": 1,
|
||||
"note": "product:search"
|
||||
},
|
||||
{
|
||||
"kind": "dense",
|
||||
"items": 1,
|
||||
"note": "product:batch:add"
|
||||
},
|
||||
{
|
||||
"kind": "dense",
|
||||
"items": 1,
|
||||
"note": "product:add"
|
||||
}
|
||||
],
|
||||
"final_embed_rows": [
|
||||
{
|
||||
"kind": "authority_prefix",
|
||||
"items": 0,
|
||||
"note": "authority:synthetic-verify-prefix"
|
||||
},
|
||||
{
|
||||
"kind": "dense",
|
||||
"items": 1,
|
||||
"note": "product:search"
|
||||
},
|
||||
{
|
||||
"kind": "dense",
|
||||
"items": 1,
|
||||
"note": "product:batch:add"
|
||||
},
|
||||
{
|
||||
"kind": "dense",
|
||||
"items": 1,
|
||||
"note": "product:add"
|
||||
},
|
||||
{
|
||||
"kind": "dense",
|
||||
"items": 1,
|
||||
"note": "product:search"
|
||||
},
|
||||
{
|
||||
"kind": "dense",
|
||||
"items": 1,
|
||||
"note": "product:batch:add"
|
||||
},
|
||||
{
|
||||
"kind": "dense",
|
||||
"items": 1,
|
||||
"note": "product:add"
|
||||
},
|
||||
{
|
||||
"kind": "dense",
|
||||
"items": 1,
|
||||
"note": "product:search"
|
||||
},
|
||||
{
|
||||
"kind": "dense",
|
||||
"items": 1,
|
||||
"note": "product:batch:add"
|
||||
},
|
||||
{
|
||||
"kind": "dense",
|
||||
"items": 1,
|
||||
"note": "product:add"
|
||||
},
|
||||
{
|
||||
"kind": "dense",
|
||||
"items": 1,
|
||||
"note": "product:search"
|
||||
},
|
||||
{
|
||||
"kind": "dense",
|
||||
"items": 1,
|
||||
"note": "product:search"
|
||||
}
|
||||
],
|
||||
"final_llm_used": 3,
|
||||
"finished": "2026-10-26T19:35:47Z",
|
||||
"gateway_requests_total": 3,
|
||||
"failures": [],
|
||||
"temp_dir": "/tmp/multica-task-29494715/hel874-real-sdk-8dkofioe"
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
{
|
||||
"head": "HEL-885 rework",
|
||||
"real_llm_requests": 0,
|
||||
"real_embeddings": 0,
|
||||
"boundary": "deterministic 512 vectors, non-loopback forbidden",
|
||||
"checks": [
|
||||
{
|
||||
"name": "S0_positive_caps_without_authority_fail_closed",
|
||||
"ok": true,
|
||||
"detail": "missing=ledger_authority_required empty=ledger_authority_required"
|
||||
},
|
||||
{
|
||||
"name": "S1_p1_first_tick_partial",
|
||||
"ok": true,
|
||||
"detail": "state=queued reason=LLM extraction failed: semantic_llm_budget_exhausted http=1 completed=[2] points=1 per_row_anchor=True"
|
||||
},
|
||||
{
|
||||
"name": "S2_p1_restart_sends_only_missing_row",
|
||||
"ok": true,
|
||||
"detail": "state=done http=1 user_sent=True completed=[1, 2] entry_ids=[\"07401cdd-4964-4c74-aab5-516ab09cf5e4\", \"4d76b52d-186c-4b21-8bfa-e81341213589\"]"
|
||||
},
|
||||
{
|
||||
"name": "S3a_lease_expired_batch_recovers",
|
||||
"ok": true,
|
||||
"detail": "recovered={'state': 'failed', 'reason': 'lease_expired'} state_after=done http=2"
|
||||
},
|
||||
{
|
||||
"name": "S3b_concurrent_ticks_single_send",
|
||||
"ok": true,
|
||||
"detail": "http=2 states=['done']"
|
||||
},
|
||||
{
|
||||
"name": "S4a_aged_unknown_llm_reservation_kept",
|
||||
"ok": true,
|
||||
"detail": "second_allowed=False used_after_restart=1"
|
||||
},
|
||||
{
|
||||
"name": "S4b_aged_unknown_embed_reservation_kept",
|
||||
"ok": true,
|
||||
"detail": "second_allowed=False used=1 after_release=0"
|
||||
}
|
||||
],
|
||||
"gateway_requests_total": 6,
|
||||
"failures": []
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
{
|
||||
"head": "HEL-889 shutdown ownership & queued-cancel",
|
||||
"real_llm_requests": 0,
|
||||
"real_embeddings": 0,
|
||||
"boundary": "deterministic 512 vectors, non-loopback forbidden",
|
||||
"checks": [
|
||||
{
|
||||
"name": "Q1 queued snapshot shows phantom-liveness",
|
||||
"ok": true,
|
||||
"detail": ""
|
||||
},
|
||||
{
|
||||
"name": "Q1 cancel releases registry and requeues",
|
||||
"ok": true,
|
||||
"detail": "{\"registered_workers\": 0, \"batch\": {\"state\": \"queued\", \"reason\": \"queued_worker_cancelled\", \"owner\": null, \"attempts\": 0, \"entry_ids\": null}, \"row_done\": 0, \"stored_entries\": 0}"
|
||||
},
|
||||
{
|
||||
"name": "Q1 in-process recovery completes without restart",
|
||||
"ok": true,
|
||||
"detail": "{\"batch\": {\"state\": \"done\", \"reason\": null, \"owner\": null, \"attempts\": 1, \"entry_ids\": \"[\\\"stub-1\\\"]\"}, \"registered_workers\": 0, \"stored_entries\": 1, \"row_done\": 1}"
|
||||
},
|
||||
{
|
||||
"name": "S1 aclose does NOT return while the worker is alive",
|
||||
"ok": true,
|
||||
"detail": ""
|
||||
},
|
||||
{
|
||||
"name": "S1 worker completes and flushes before store close",
|
||||
"ok": true,
|
||||
"detail": "{\"state\": \"done\", \"reason\": null, \"owner\": null, \"attempts\": 1, \"entry_ids\": \"[\\\"19039615-6f32-48e6-979b-715d2cd56fcb\\\"]\"}"
|
||||
},
|
||||
{
|
||||
"name": "S1 no late-worker error after honest drain",
|
||||
"ok": true,
|
||||
"detail": ""
|
||||
},
|
||||
{
|
||||
"name": "S1 durable reopen: done + row_done=1 + llm_used=1",
|
||||
"ok": true,
|
||||
"detail": "{\"state\": \"done\", \"reason\": null, \"owner\": null, \"attempts\": 1, \"entry_ids\": \"[\\\"19039615-6f32-48e6-979b-715d2cd56fcb\\\"]\", \"row_done\": 1, \"llm_used\": 1, \"gateway_posts\": 1}"
|
||||
},
|
||||
{
|
||||
"name": "S2 shutdown between rows requeues with first row proven",
|
||||
"ok": true,
|
||||
"detail": "{\"state\": \"queued\", \"reason\": \"shutdown_between_rows\", \"owner\": null, \"attempts\": 0, \"entry_ids\": null, \"row_done\": 1, \"gateway_posts_during_shutdown\": 1}"
|
||||
},
|
||||
{
|
||||
"name": "S2 resume sends ONLY the missing row and completes",
|
||||
"ok": true,
|
||||
"detail": "{\"state\": \"done\", \"reason\": null, \"owner\": null, \"attempts\": 1, \"entry_ids\": \"[\\\"f26d374a-858e-4dde-b2de-ae8af7057021\\\", \\\"258ab9a5-d523-45b0-ada1-d58fbda50ea7\\\"]\", \"row_done\": 2, \"gateway_posts_resume\": 2}"
|
||||
},
|
||||
{
|
||||
"name": "S3 cancelled aclose closes nothing and re-arms",
|
||||
"ok": true,
|
||||
"detail": ""
|
||||
},
|
||||
{
|
||||
"name": "S3 worker finishes done and a later aclose closes for real",
|
||||
"ok": true,
|
||||
"detail": ""
|
||||
},
|
||||
{
|
||||
"name": "S4 concurrent aclose drains once and closes once",
|
||||
"ok": true,
|
||||
"detail": "{\"batch\": {\"state\": \"done\", \"reason\": null, \"owner\": null, \"attempts\": 1, \"entry_ids\": \"[\\\"e553422c-1840-4ff4-b51c-a3586cc34179\\\"]\", \"row_done\": 1}, \"client_usable_after_close\": false}"
|
||||
}
|
||||
],
|
||||
"queued_cancel": {
|
||||
"queued": {
|
||||
"registered_workers": 1,
|
||||
"product_executor_queue": 1
|
||||
},
|
||||
"after_cancel": {
|
||||
"registered_workers": 0,
|
||||
"batch": {
|
||||
"state": "queued",
|
||||
"reason": "queued_worker_cancelled",
|
||||
"owner": null,
|
||||
"attempts": 0,
|
||||
"entry_ids": null
|
||||
},
|
||||
"row_done": 0,
|
||||
"stored_entries": 0
|
||||
},
|
||||
"after_recovery": {
|
||||
"batch": {
|
||||
"state": "done",
|
||||
"reason": null,
|
||||
"owner": null,
|
||||
"attempts": 1,
|
||||
"entry_ids": "[\"stub-1\"]"
|
||||
},
|
||||
"registered_workers": 0,
|
||||
"stored_entries": 1,
|
||||
"row_done": 1
|
||||
}
|
||||
},
|
||||
"shutdown_timeout": {
|
||||
"deadline": {
|
||||
"aclose_returned_while_worker_alive": false,
|
||||
"batch_before_any_close": {
|
||||
"state": "pending",
|
||||
"reason": null,
|
||||
"owner": "4a048d364194a961365c30ee1e570233",
|
||||
"attempts": 1,
|
||||
"entry_ids": null
|
||||
},
|
||||
"client_usable": true
|
||||
},
|
||||
"before_store_close": {
|
||||
"state": "done",
|
||||
"reason": null,
|
||||
"owner": null,
|
||||
"attempts": 1,
|
||||
"entry_ids": "[\"19039615-6f32-48e6-979b-715d2cd56fcb\"]"
|
||||
},
|
||||
"late_worker_error": null,
|
||||
"persisted": {
|
||||
"state": "done",
|
||||
"reason": null,
|
||||
"owner": null,
|
||||
"attempts": 1,
|
||||
"entry_ids": "[\"19039615-6f32-48e6-979b-715d2cd56fcb\"]",
|
||||
"row_done": 1,
|
||||
"llm_used": 1,
|
||||
"gateway_posts": 1
|
||||
}
|
||||
},
|
||||
"between_rows": {
|
||||
"after_shutdown": {
|
||||
"state": "queued",
|
||||
"reason": "shutdown_between_rows",
|
||||
"owner": null,
|
||||
"attempts": 0,
|
||||
"entry_ids": null,
|
||||
"row_done": 1,
|
||||
"gateway_posts_during_shutdown": 1
|
||||
},
|
||||
"after_resume": {
|
||||
"state": "done",
|
||||
"reason": null,
|
||||
"owner": null,
|
||||
"attempts": 1,
|
||||
"entry_ids": "[\"f26d374a-858e-4dde-b2de-ae8af7057021\", \"258ab9a5-d523-45b0-ada1-d58fbda50ea7\"]",
|
||||
"row_done": 2,
|
||||
"gateway_posts_resume": 2
|
||||
}
|
||||
},
|
||||
"cancelled_aclose": {
|
||||
"after_cancel": {
|
||||
"client_usable": true,
|
||||
"batch": {
|
||||
"state": "pending",
|
||||
"reason": null,
|
||||
"owner": "a712e0367aa123b265b47e2d3223846a",
|
||||
"attempts": 1,
|
||||
"entry_ids": null
|
||||
},
|
||||
"closing_cleared": true
|
||||
},
|
||||
"after_worker": {
|
||||
"state": "done",
|
||||
"reason": null,
|
||||
"owner": null,
|
||||
"attempts": 1,
|
||||
"entry_ids": "[\"73f87468-f546-46d7-8116-37d4fe2818b1\"]"
|
||||
},
|
||||
"client_usable_after_real_close": false
|
||||
},
|
||||
"concurrent_aclose": {
|
||||
"batch": {
|
||||
"state": "done",
|
||||
"reason": null,
|
||||
"owner": null,
|
||||
"attempts": 1,
|
||||
"entry_ids": "[\"e553422c-1840-4ff4-b51c-a3586cc34179\"]",
|
||||
"row_done": 1
|
||||
},
|
||||
"client_usable_after_close": false
|
||||
},
|
||||
"failures": []
|
||||
}
|
||||
@@ -0,0 +1,161 @@
|
||||
{
|
||||
"card": "HEL-879",
|
||||
"generated_by": "release-artifacts inventory (offline, zero downloads)",
|
||||
"release_code_commit": "01ff91985920162cddabc5f190d146d86793627d",
|
||||
"rework_head": "see delivery comment (branch hel-879-assembly, appended after 7f0a739; this inventory refreshed on that head)",
|
||||
"audit_evidence": "docs/rework/hel879/sdk-audit/sdk-audit.json (head c121c42e39174e0f627f129e7f7e5700f33acf26)",
|
||||
"single_install_entry": "deploy/hel895-release-candidate.md #4 (supersedes deploy/hel874-release.md #4)",
|
||||
"fixed_source": {
|
||||
"artifact": "/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-857-2cf6dc7dfc87/workdir/hel857-data/mem0-2c81af3.tar.gz",
|
||||
"sha256": "9dcef9303ebcec116eec6739f01b8b35bd24459de6a569686b4d19b9412dda23",
|
||||
"lock_record": "deploy/mem0-stack.lock: 9dcef9303ebcec116eec6739f01b8b35bd24459de6a569686b4d19b9412dda23",
|
||||
"matches_lock": true,
|
||||
"source_commit": "2c81af3bbe27d9bccb09c772d583df9e9be72ee5"
|
||||
},
|
||||
"closure": {
|
||||
"total": 55,
|
||||
"missing": 41,
|
||||
"missing_pure_python": [
|
||||
"backoff",
|
||||
"coloredlogs",
|
||||
"distro",
|
||||
"fastembed",
|
||||
"filelock",
|
||||
"flatbuffers",
|
||||
"fsspec",
|
||||
"h2",
|
||||
"hpack",
|
||||
"httpcore2",
|
||||
"httpx2",
|
||||
"huggingface-hub",
|
||||
"humanfriendly",
|
||||
"hyperframe",
|
||||
"loguru",
|
||||
"mem0ai",
|
||||
"mpmath",
|
||||
"openai",
|
||||
"portalocker",
|
||||
"posthog",
|
||||
"pytz",
|
||||
"qdrant-client",
|
||||
"requests",
|
||||
"sniffio",
|
||||
"sympy",
|
||||
"tqdm",
|
||||
"truststore",
|
||||
"urllib3"
|
||||
],
|
||||
"missing_native": [
|
||||
"charset-normalizer",
|
||||
"greenlet",
|
||||
"grpcio",
|
||||
"hf-xet",
|
||||
"jiter",
|
||||
"mmh3",
|
||||
"numpy",
|
||||
"onnxruntime",
|
||||
"pillow",
|
||||
"protobuf",
|
||||
"py-rust-stemmers",
|
||||
"sqlalchemy",
|
||||
"tokenizers"
|
||||
]
|
||||
},
|
||||
"cache_reusable_reverified": [
|
||||
{
|
||||
"name": "greenlet",
|
||||
"version": "3.5.6",
|
||||
"cache_hits": [
|
||||
{
|
||||
"kind": "uv:wheels-v7",
|
||||
"entry": "3.5.6-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64",
|
||||
"content_digest": "d7ae14625784af8a268e8c156533b2e9d7694680e80a8466c8e5808cc3f1a005"
|
||||
},
|
||||
{
|
||||
"kind": "uv:wheels-v6",
|
||||
"entry": "3.5.6-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64",
|
||||
"content_digest": "2fc3afa56933ea2cbaf6005c1e61565e769db1f202b3d8c53a67e59a2ed307f7"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "pillow",
|
||||
"version": "12.3.0",
|
||||
"cache_hits": [
|
||||
{
|
||||
"kind": "uv:wheels-v7",
|
||||
"entry": "12.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64",
|
||||
"content_digest": "02620d3560d2e91e0920c1045ed814b02a4d15d8c1c960f43a060739acf0dc1f"
|
||||
},
|
||||
{
|
||||
"kind": "uv:wheels-v6",
|
||||
"entry": "12.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64",
|
||||
"content_digest": "657f02aee576df196a22c130a65a3dd0f7438a8b859c2221448bea2dac6d7112"
|
||||
},
|
||||
{
|
||||
"kind": "uv:wheels-v6",
|
||||
"entry": "12.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64",
|
||||
"content_digest": "02620d3560d2e91e0920c1045ed814b02a4d15d8c1c960f43a060739acf0dc1f"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "truststore",
|
||||
"version": "0.10.5",
|
||||
"cache_hits": [
|
||||
{
|
||||
"kind": "uv:wheels-v7",
|
||||
"entry": "0.10.5-py3-none-any",
|
||||
"content_digest": "54c5d4c83a1183954a6ca33169f8881c576160c722e93064ece271776ee2eac4"
|
||||
},
|
||||
{
|
||||
"kind": "uv:wheels-v6",
|
||||
"entry": "0.10.5-py3-none-any",
|
||||
"content_digest": "54c5d4c83a1183954a6ca33169f8881c576160c722e93064ece271776ee2eac4"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"build_backend": {
|
||||
"hatchling_cached_or_local": true,
|
||||
"hatchling_version": "1.32.4",
|
||||
"hatchling_cache_evidence": [
|
||||
"uv wheels-v6: ~/.cache/uv/wheels-v6/pypi/hatchling/1.32.4-py3-none-any",
|
||||
"uv wheels-v7: ~/.cache/uv/wheels-v7/pypi/hatchling/1.32.4-py3-none-any",
|
||||
"uv archive-v0 unpacked: hatchling-1.32.4.dist-info (wheels-v6 + wheels-v7 linked copies)"
|
||||
],
|
||||
"offline_wheel_built": {
|
||||
"built_at": "2026-10-27T04:10:00Z",
|
||||
"command": "cd <extracted mem0-2c81af3 tarball> && uv build --wheel --offline --python 3.11 -o <out>",
|
||||
"tool": "uv 0.13.5, uv-managed CPython 3.11.16, build backend hatchling from the offline cache only",
|
||||
"source_tarball_sha256": "9dcef9303ebcec116eec6739f01b8b35bd24459de6a569686b4d19b9412dda23",
|
||||
"source_commit": "2c81af3bbe27d9bccb09c772d583df9e9be72ee5",
|
||||
"wheel": "mem0ai-2.2.1-py3-none-any.whl",
|
||||
"wheel_sha256": "698284b6083ab8b7761454d65876a6d1bb983d278ad21a7bee38d760cb20e9db",
|
||||
"wheel_bytes": 352586,
|
||||
"wheel_files": 153,
|
||||
"installed_anywhere": false,
|
||||
"network_used": false,
|
||||
"note": "HEL-879 勘误:v1 清单一面写 hatchling_cached_or_local=true 一面又称本机缺 hatchling,并把 hatchling 列入待下载——总管只读核查指出 uv v6/v7 均有 1.32.4 缓存。已核实并直接完成可离线构建:固定源码 tarball(sha 与 lock 一致)经缓存 hatchling 离线构建出上面这只 wheel,未安装、未联网、未混 3.10 site-packages。待下载清单据此只余 41 项运行闭包(不含 hatchling)。"
|
||||
}
|
||||
},
|
||||
"fastembed_models": {
|
||||
"cache_dir": "/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-857-2cf6dc7dfc87/workdir/hel857-data/fastembed-cache",
|
||||
"exists": true,
|
||||
"models": {
|
||||
"models--Qdrant--bge-small-zh-v1.5": {
|
||||
"files": 13,
|
||||
"bytes": 190444780
|
||||
},
|
||||
"models--Qdrant--bm25": {
|
||||
"files": 39,
|
||||
"bytes": 56247
|
||||
}
|
||||
},
|
||||
"default_cache_dir": "/home/xiaomo/.cache/fastembed",
|
||||
"default_cache_exists": false,
|
||||
"release_note": "真实 mem0 模式把 fastembed cache_dir 指向发布实例数据目录内的该缓存拷贝;本次零下载、不推理"
|
||||
},
|
||||
"downloads_this_card": 0,
|
||||
"note": "产物清单以 release_code_commit 为准;不要用旧父提交(04eff61/152479b/c121c42)说明冒充该 head。缓存命中为解包目录时记录内容摘要(目录无单一 sha256),安装时以 --offline 命中为准。"
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
{
|
||||
"started": "2026-10-26T19:35:15Z",
|
||||
"venv_python": "/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-879-3c721d56b938/workdir/CyberGril/.venv311/bin/python",
|
||||
"venv_python_version": "3.11.16",
|
||||
"checks": [
|
||||
{
|
||||
"name": "R1_checkout_fresh_dir",
|
||||
"ok": true,
|
||||
"detail": "cloned tracked source into /tmp/multica-task-29494715/hel882-release-jk7k2a25/cybergril-hel874/current"
|
||||
},
|
||||
{
|
||||
"name": "R2_service_imports_product",
|
||||
"ok": true,
|
||||
"detail": ""
|
||||
},
|
||||
{
|
||||
"name": "R6_mem0_coimport_status_recorded",
|
||||
"ok": true,
|
||||
"detail": "import mem0 → ModuleNotFoundError: No module named 'mem0' (resolution path in deploy/hel874-release.md §4; no download in this check)"
|
||||
},
|
||||
{
|
||||
"name": "R7_pip_download_command_exists",
|
||||
"ok": true,
|
||||
"detail": "/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-879-3c721d56b938/workdir/CyberGril/.venv311/bin/python -m pip download --help → rc=0"
|
||||
},
|
||||
{
|
||||
"name": "R7_removed_uv_pip_download_still_absent",
|
||||
"ok": true,
|
||||
"detail": "uv pip download --help → rc=2 (kept absent on purpose; do not re-document it)"
|
||||
},
|
||||
{
|
||||
"name": "R2_service_serves_health",
|
||||
"ok": true,
|
||||
"detail": "version=R4-assembly semantic=stub"
|
||||
},
|
||||
{
|
||||
"name": "R3_create_status_recorded",
|
||||
"ok": true,
|
||||
"detail": "create status=201(409=前次运行的档案仍在,也是保留数据的表现)"
|
||||
},
|
||||
{
|
||||
"name": "R3_dialogue_refused_honestly",
|
||||
"ok": true,
|
||||
"detail": "http=200 events=b'data: {\"t\": \"chat.error\", \"epoch\": 1, \"turn_id\": \"00000000-0000-4000-8000-000000000001\", \"phi\": \"\\xe5\\xa5\\xb9\\xe8\\xbf\\x99\\xe4\\xbc\\x9a\\xe5\\x84\\xbf\\xe6\\xb2\\xa1\\xe6\\x8e\\xa5\\xe4\\xb8\\x8a\\xe8\\xaf'"
|
||||
},
|
||||
{
|
||||
"name": "R4_service_restarts_on_same_data",
|
||||
"ok": true,
|
||||
"detail": "epoch=2"
|
||||
},
|
||||
{
|
||||
"name": "R5_epoch_bumped_on_reopen",
|
||||
"ok": true,
|
||||
"detail": "1 → 2"
|
||||
},
|
||||
{
|
||||
"name": "R4_companion_created_offline",
|
||||
"ok": true,
|
||||
"detail": "status=409"
|
||||
},
|
||||
{
|
||||
"name": "R4_dialogue_stream_http",
|
||||
"ok": true,
|
||||
"detail": "status=200 events=b'data: {\"t\": \"chat.delta\", \"epoch\": 2, \"turn_id\": \"00000000-0000-4000-8000-000000000002\", \"delta\": \"\\xe6\\x89\\xb9\"}\\n\\ndata: {\"t\": \"c'"
|
||||
},
|
||||
{
|
||||
"name": "R4_messages_roundtrip",
|
||||
"ok": true,
|
||||
"detail": "roles=['user', 'user', 'companion']"
|
||||
},
|
||||
{
|
||||
"name": "R5_data_dir_preserved",
|
||||
"ok": true,
|
||||
"detail": "['companion.db']"
|
||||
},
|
||||
{
|
||||
"name": "R5_companion_row_survives_restart",
|
||||
"ok": true,
|
||||
"detail": "companion rows=1"
|
||||
}
|
||||
],
|
||||
"mem0_import_in_release_venv": "ModuleNotFoundError: No module named 'mem0'",
|
||||
"removed_uv_pip_download_rc": 2,
|
||||
"failures": [],
|
||||
"finished": "2026-10-26T19:35:18Z"
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"ok": true,
|
||||
"code_commit": "7c73d392b95f3d55091a066db0ffe9bc6c475e0d",
|
||||
"tool_version": 3,
|
||||
"checks": [
|
||||
{
|
||||
"name": "naive_online_copy_loses_wal_reproduced",
|
||||
"ok": true,
|
||||
"detail": "error=no such table: companion"
|
||||
},
|
||||
{
|
||||
"name": "busy_checkpoint_state_reproduced",
|
||||
"ok": true,
|
||||
"detail": "checkpoint=(1, 9, 8) naive_snapshot_events=error=DatabaseError:database disk image is malformed"
|
||||
},
|
||||
{
|
||||
"name": "fix1_busy_checkpoint_fails_no_archive",
|
||||
"ok": true,
|
||||
"detail": "error=yes leftovers=0"
|
||||
},
|
||||
{
|
||||
"name": "fix1b_row_mismatch_fails_no_archive",
|
||||
"ok": true,
|
||||
"detail": "error=源/快照行数不一致,不打包:/tmp/multica-task-3939683741/hel879-snapshot-s artifacts=[]"
|
||||
},
|
||||
{
|
||||
"name": "fix_verify_rejects_rows_match_false_legacy_package",
|
||||
"ok": true,
|
||||
"detail": "ok=False checks=[{'db': 'databases/companion.db', 'restored': '/tmp/multica-task-3939683741/hel879-snapshot-selftest-a4xt_3p_/verify-restore-legacy-pkg.tar-20261027-042723/by-source/tmp__multica-task-3939683741__hel879-snapshot-selftest-a4xt_3p___instance__companion.db', 'sha256_ok': True, 'rows_ok': False, 'counts': {'companion': 1, 'chat_message': 1, 'events': 1}, 'source_counts': {'companion': 1, 'chat_message': 1, 'events': 1}, 'snapshot_counts': {'companion': 1, 'chat_message': 1, 'events': 0}, 'rows_match_recorded': False, 'rejected_legacy_package': True}]"
|
||||
},
|
||||
{
|
||||
"name": "fix2_online_mode_refuses_dir_with_sqlite",
|
||||
"ok": true,
|
||||
"detail": "在线模式只允许显式单库 backup API(--db);--file /tmp/multica-task-3939683741/hel879-snapshot-selftest-a4xt_3p_/instance/history_root"
|
||||
},
|
||||
{
|
||||
"name": "fix2_stop_mode_embeds_sqlite_via_consistency_path",
|
||||
"ok": true,
|
||||
"detail": "embedded=['/tmp/multica-task-3939683741/hel879-snapshot-selftest-a4xt_3p_/instance/history_root/mem0_public_history.db']"
|
||||
},
|
||||
{
|
||||
"name": "fix3_verify_maps_source_paths_and_passes",
|
||||
"ok": true,
|
||||
"detail": "ok=True commit=7c73d392b95f3d55091a066db0ffe9bc6c475e0d plan_entries=4"
|
||||
},
|
||||
{
|
||||
"name": "backup_api_snapshot_complete",
|
||||
"ok": true,
|
||||
"detail": "{\"companion\": 1, \"chat_message\": 1, \"events\": 1}"
|
||||
},
|
||||
{
|
||||
"name": "fix_rows_match_true_cannot_bypass_source_counts",
|
||||
"ok": true,
|
||||
"detail": "ok=False counts={'companion': 1, 'chat_message': 1, 'events': 1} source={'companion': 1, 'chat_message': 1, 'events': 2}"
|
||||
},
|
||||
{
|
||||
"name": "fix_same_basename_no_overwrite_and_duplicate_refused",
|
||||
"ok": true,
|
||||
"detail": "snap_names=['ledger.db', 'ledger__0e75f128.db'] verify_ok=True restored_rows=['first', 'second'] dup_refused=yes"
|
||||
},
|
||||
{
|
||||
"name": "restore_drill_paths_persist",
|
||||
"ok": true,
|
||||
"detail": "restore_root=/tmp/multica-task-3939683741/hel879-snapshot-selftest-a4xt_3p_/same-restore"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,886 @@
|
||||
{
|
||||
"head": "7c73d392b95f3d55091a066db0ffe9bc6c475e0d",
|
||||
"scope": "只读审计:3.10 固定栈安装元数据按 3.11 Linux markers+extras 求闭包,对照产品 3.11 venv 与本机 uv/pip 缓存;这是依赖闭包清单,不是已完成的 cp311 解析或下载结果",
|
||||
"read_only": true,
|
||||
"zero_downloads_this_card": true,
|
||||
"closure_total": 55,
|
||||
"missing_count": 41,
|
||||
"missing_pure_python": [
|
||||
"backoff",
|
||||
"coloredlogs",
|
||||
"distro",
|
||||
"fastembed",
|
||||
"filelock",
|
||||
"flatbuffers",
|
||||
"fsspec",
|
||||
"h2",
|
||||
"hpack",
|
||||
"httpcore2",
|
||||
"httpx2",
|
||||
"huggingface-hub",
|
||||
"humanfriendly",
|
||||
"hyperframe",
|
||||
"loguru",
|
||||
"mem0ai",
|
||||
"mpmath",
|
||||
"openai",
|
||||
"portalocker",
|
||||
"posthog",
|
||||
"pytz",
|
||||
"qdrant-client",
|
||||
"requests",
|
||||
"sniffio",
|
||||
"sympy",
|
||||
"tqdm",
|
||||
"truststore",
|
||||
"urllib3"
|
||||
],
|
||||
"missing_native": [
|
||||
"charset-normalizer",
|
||||
"greenlet",
|
||||
"grpcio",
|
||||
"hf-xet",
|
||||
"jiter",
|
||||
"mmh3",
|
||||
"numpy",
|
||||
"onnxruntime",
|
||||
"pillow",
|
||||
"protobuf",
|
||||
"py-rust-stemmers",
|
||||
"sqlalchemy",
|
||||
"tokenizers"
|
||||
],
|
||||
"cache_reusable_now": [
|
||||
"greenlet",
|
||||
"pillow",
|
||||
"truststore"
|
||||
],
|
||||
"top_level": {
|
||||
"mem0ai": {
|
||||
"name": "mem0ai",
|
||||
"version": "2.2.1",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": "{\"dir_info\": {}, \"url\": \"file:///home/xiaomo/multica_workspaces/hello-af23464d222e/hel-857-2cf6dc7dfc87/workdir/hel857-src\"}",
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "fixed-source"
|
||||
},
|
||||
"qdrant-client": {
|
||||
"name": "qdrant-client",
|
||||
"version": "1.20.0",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
"fastembed": {
|
||||
"name": "fastembed",
|
||||
"version": "0.9.1",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
}
|
||||
},
|
||||
"missing_detail": [
|
||||
{
|
||||
"name": "backoff",
|
||||
"version": "2.2.1",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "charset-normalizer",
|
||||
"version": "3.5.2",
|
||||
"wheel_tags": [
|
||||
"cp310-cp310-manylinux_2_17_x86_64",
|
||||
"cp310-cp310-manylinux2014_x86_64",
|
||||
"cp310-cp310-manylinux_2_28_x86_64"
|
||||
],
|
||||
"native_extension": true,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "3.11 目标需 cp311-cp311(或 cp39+ abi3)manylinux x86_64 原生 wheel;3.10 安装标签不可复制,禁混 site-packages",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "coloredlogs",
|
||||
"version": "15.0.1",
|
||||
"wheel_tags": [
|
||||
"py2-none-any",
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "distro",
|
||||
"version": "1.9.0",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "fastembed",
|
||||
"version": "0.9.1",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "filelock",
|
||||
"version": "4.1.0",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "flatbuffers",
|
||||
"version": "25.12.19",
|
||||
"wheel_tags": [
|
||||
"py2-none-any",
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "fsspec",
|
||||
"version": "2026.9.0",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "greenlet",
|
||||
"version": "3.5.6",
|
||||
"wheel_tags": [
|
||||
"cp310-cp310-manylinux_2_24_x86_64",
|
||||
"cp310-cp310-manylinux_2_28_x86_64"
|
||||
],
|
||||
"native_extension": true,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [
|
||||
{
|
||||
"kind": "uv:wheels-v7",
|
||||
"path": "/home/xiaomo/.cache/uv/wheels-v7/pypi/greenlet/3.5.6-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64",
|
||||
"name": "3.5.6-cp312-cp312-manylinux_2_24_x86_64.manylinux_2_28_x86_64",
|
||||
"sha256": null
|
||||
},
|
||||
{
|
||||
"kind": "uv:wheels-v6",
|
||||
"path": "/home/xiaomo/.cache/uv/wheels-v6/pypi/greenlet/3.5.6-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64",
|
||||
"name": "3.5.6-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64",
|
||||
"sha256": null
|
||||
}
|
||||
],
|
||||
"cache_hits_usable_for_311": [
|
||||
"3.5.6-cp311-cp311-manylinux_2_24_x86_64.manylinux_2_28_x86_64"
|
||||
],
|
||||
"resolution": "3.11 目标需 cp311-cp311(或 cp39+ abi3)manylinux x86_64 原生 wheel;3.10 安装标签不可复制,禁混 site-packages",
|
||||
"classification": "cache-reusable"
|
||||
},
|
||||
{
|
||||
"name": "grpcio",
|
||||
"version": "1.84.1",
|
||||
"wheel_tags": [
|
||||
"cp310-cp310-manylinux_2_17_x86_64",
|
||||
"cp310-cp310-manylinux2014_x86_64"
|
||||
],
|
||||
"native_extension": true,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "3.11 目标需 cp311-cp311(或 cp39+ abi3)manylinux x86_64 原生 wheel;3.10 安装标签不可复制,禁混 site-packages",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "h2",
|
||||
"version": "4.4.1",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "hf-xet",
|
||||
"version": "1.7.0",
|
||||
"wheel_tags": [
|
||||
"cp38-abi3-manylinux_2_17_x86_64",
|
||||
"cp38-abi3-manylinux2014_x86_64"
|
||||
],
|
||||
"native_extension": true,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "3.11 目标需 cp311-cp311(或 cp39+ abi3)manylinux x86_64 原生 wheel;3.10 安装标签不可复制,禁混 site-packages",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "hpack",
|
||||
"version": "4.2.0",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "httpcore2",
|
||||
"version": "2.14.0",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "httpx2",
|
||||
"version": "2.14.0",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "huggingface-hub",
|
||||
"version": "1.33.0",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "humanfriendly",
|
||||
"version": "10.0",
|
||||
"wheel_tags": [
|
||||
"py2-none-any",
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "hyperframe",
|
||||
"version": "6.1.0",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "jiter",
|
||||
"version": "0.18.0",
|
||||
"wheel_tags": [
|
||||
"cp310-cp310-manylinux_2_17_x86_64",
|
||||
"cp310-cp310-manylinux2014_x86_64"
|
||||
],
|
||||
"native_extension": true,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "3.11 目标需 cp311-cp311(或 cp39+ abi3)manylinux x86_64 原生 wheel;3.10 安装标签不可复制,禁混 site-packages",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "loguru",
|
||||
"version": "0.7.3",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "mem0ai",
|
||||
"version": "2.2.1",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": "{\"dir_info\": {}, \"url\": \"file:///home/xiaomo/multica_workspaces/hello-af23464d222e/hel-857-2cf6dc7dfc87/workdir/hel857-src\"}",
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "fixed-source"
|
||||
},
|
||||
{
|
||||
"name": "mmh3",
|
||||
"version": "5.3.1",
|
||||
"wheel_tags": [
|
||||
"cp310-cp310-manylinux_2_5_x86_64",
|
||||
"cp310-cp310-manylinux1_x86_64",
|
||||
"cp310-cp310-manylinux_2_28_x86_64"
|
||||
],
|
||||
"native_extension": true,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "3.11 目标需 cp311-cp311(或 cp39+ abi3)manylinux x86_64 原生 wheel;3.10 安装标签不可复制,禁混 site-packages",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "mpmath",
|
||||
"version": "1.3.0",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "numpy",
|
||||
"version": "2.2.6",
|
||||
"wheel_tags": [
|
||||
"cp310-cp310-manylinux_2_17_x86_64",
|
||||
"cp310-cp310-manylinux2014_x86_64"
|
||||
],
|
||||
"native_extension": true,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "3.11 目标需 cp311-cp311(或 cp39+ abi3)manylinux x86_64 原生 wheel;3.10 安装标签不可复制,禁混 site-packages",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "onnxruntime",
|
||||
"version": "1.23.2",
|
||||
"wheel_tags": [
|
||||
"cp310-cp310-manylinux_2_27_x86_64",
|
||||
"cp310-cp310-manylinux_2_28_x86_64"
|
||||
],
|
||||
"native_extension": true,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "3.11 目标需 cp311-cp311(或 cp39+ abi3)manylinux x86_64 原生 wheel;3.10 安装标签不可复制,禁混 site-packages",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "openai",
|
||||
"version": "3.37.0",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "pillow",
|
||||
"version": "12.3.0",
|
||||
"wheel_tags": [
|
||||
"cp310-cp310-manylinux_2_27_x86_64",
|
||||
"cp310-cp310-manylinux_2_28_x86_64"
|
||||
],
|
||||
"native_extension": true,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [
|
||||
{
|
||||
"kind": "uv:wheels-v7",
|
||||
"path": "/home/xiaomo/.cache/uv/wheels-v7/pypi/pillow/12.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64",
|
||||
"name": "12.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64",
|
||||
"sha256": null
|
||||
},
|
||||
{
|
||||
"kind": "uv:wheels-v6",
|
||||
"path": "/home/xiaomo/.cache/uv/wheels-v6/pypi/pillow/12.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64",
|
||||
"name": "12.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64",
|
||||
"sha256": null
|
||||
},
|
||||
{
|
||||
"kind": "uv:wheels-v6",
|
||||
"path": "/home/xiaomo/.cache/uv/wheels-v6/pypi/pillow/12.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64",
|
||||
"name": "12.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64",
|
||||
"sha256": null
|
||||
}
|
||||
],
|
||||
"cache_hits_usable_for_311": [
|
||||
"12.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64"
|
||||
],
|
||||
"resolution": "3.11 目标需 cp311-cp311(或 cp39+ abi3)manylinux x86_64 原生 wheel;3.10 安装标签不可复制,禁混 site-packages",
|
||||
"classification": "cache-reusable"
|
||||
},
|
||||
{
|
||||
"name": "portalocker",
|
||||
"version": "4.4.1",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "posthog",
|
||||
"version": "7.75.11",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "protobuf",
|
||||
"version": "6.33.6",
|
||||
"wheel_tags": [
|
||||
"cp39-abi3-manylinux2014_x86_64"
|
||||
],
|
||||
"native_extension": true,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "3.11 目标需 cp311-cp311(或 cp39+ abi3)manylinux x86_64 原生 wheel;3.10 安装标签不可复制,禁混 site-packages",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "py-rust-stemmers",
|
||||
"version": "0.1.8",
|
||||
"wheel_tags": [
|
||||
"cp310-cp310-manylinux_2_28_x86_64"
|
||||
],
|
||||
"native_extension": true,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "3.11 目标需 cp311-cp311(或 cp39+ abi3)manylinux x86_64 原生 wheel;3.10 安装标签不可复制,禁混 site-packages",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "pytz",
|
||||
"version": "2026.5",
|
||||
"wheel_tags": [
|
||||
"py2-none-any",
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "qdrant-client",
|
||||
"version": "1.20.0",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "requests",
|
||||
"version": "2.34.2",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "sniffio",
|
||||
"version": "1.3.1",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "sqlalchemy",
|
||||
"version": "2.0.55",
|
||||
"wheel_tags": [
|
||||
"cp310-cp310-manylinux_2_17_x86_64",
|
||||
"cp310-cp310-manylinux2014_x86_64",
|
||||
"cp310-cp310-manylinux_2_28_x86_64"
|
||||
],
|
||||
"native_extension": true,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "3.11 目标需 cp311-cp311(或 cp39+ abi3)manylinux x86_64 原生 wheel;3.10 安装标签不可复制,禁混 site-packages",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "sympy",
|
||||
"version": "1.14.0",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "tokenizers",
|
||||
"version": "0.23.3",
|
||||
"wheel_tags": [
|
||||
"cp310-abi3-manylinux_2_17_x86_64",
|
||||
"cp310-abi3-manylinux2014_x86_64"
|
||||
],
|
||||
"native_extension": true,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "3.11 目标需 cp311-cp311(或 cp39+ abi3)manylinux x86_64 原生 wheel;3.10 安装标签不可复制,禁混 site-packages",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "tqdm",
|
||||
"version": "4.70.1",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
},
|
||||
{
|
||||
"name": "truststore",
|
||||
"version": "0.10.5",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [
|
||||
{
|
||||
"kind": "uv:wheels-v7",
|
||||
"path": "/home/xiaomo/.cache/uv/wheels-v7/pypi/truststore/0.10.5-py3-none-any",
|
||||
"name": "0.10.5-py3-none-any",
|
||||
"sha256": null
|
||||
},
|
||||
{
|
||||
"kind": "uv:wheels-v6",
|
||||
"path": "/home/xiaomo/.cache/uv/wheels-v6/pypi/truststore/0.10.5-py3-none-any",
|
||||
"name": "0.10.5-py3-none-any",
|
||||
"sha256": null
|
||||
}
|
||||
],
|
||||
"cache_hits_usable_for_311": [
|
||||
"0.10.5-py3-none-any",
|
||||
"0.10.5-py3-none-any"
|
||||
],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "cache-reusable"
|
||||
},
|
||||
{
|
||||
"name": "urllib3",
|
||||
"version": "2.8.0",
|
||||
"wheel_tags": [
|
||||
"py3-none-any"
|
||||
],
|
||||
"native_extension": false,
|
||||
"installed_sdk": true,
|
||||
"present_product_311": false,
|
||||
"product_version": null,
|
||||
"direct_url": null,
|
||||
"cache_hits": [],
|
||||
"cache_hits_usable_for_311": [],
|
||||
"resolution": "纯 Python py3-none-any:同版本 wheel 可跨 3.10/3.11 使用",
|
||||
"classification": "missing-download-at-release"
|
||||
}
|
||||
],
|
||||
"mem0_identity": {
|
||||
"direct_url_of_installed": "{\"dir_info\": {}, \"url\": \"file:///home/xiaomo/multica_workspaces/hello-af23464d222e/hel-857-2cf6dc7dfc87/workdir/hel857-src\"}",
|
||||
"fixed_source_dir": "/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-857-2cf6dc7dfc87/workdir/hel857-src",
|
||||
"fixed_source_dir_exists": true,
|
||||
"pinned_tarball": "/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-857-2cf6dc7dfc87/workdir/hel857-data/mem0-2c81af3.tar.gz",
|
||||
"pinned_tarball_sha256_measured": "9dcef9303ebcec116eec6739f01b8b35bd24459de6a569686b4d19b9412dda23",
|
||||
"pinned_tarball_sha256_lock": "9dcef9303ebcec116eec6739f01b8b35bd24459de6a569686b4d19b9412dda23",
|
||||
"tarball_matches_lock": true,
|
||||
"index_wheel_2_2_1_proves_same_code": false,
|
||||
"note": "索引下载的 mem0ai==2.2.1 wheel 不自动等于固定源码;发布必须用本 tarball/源码目录离线构建安装",
|
||||
"built_wheel_from_hel857_install": {
|
||||
"filename": "mem0ai-2.2.1-py3-none-any.whl",
|
||||
"size": 352586,
|
||||
"sha256": "698284b6083ab8b7761454d65876a6d1bb983d278ad21a7bee38d760cb20e9db",
|
||||
"ephemeral_wheel_cache": "/tmp/multica-task-1816511421 (不再存在)",
|
||||
"persisted_anywhere": false
|
||||
},
|
||||
"offline_build_backend": {
|
||||
"hatchling_cached_or_local": true,
|
||||
"note": "离线构建 mem0 wheel 需要 hatchling 及其依赖可离线获得;未命中则发布卡需一并拉取"
|
||||
}
|
||||
},
|
||||
"fastembed_models": {
|
||||
"cache_dir": "/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-857-2cf6dc7dfc87/workdir/hel857-data/fastembed-cache",
|
||||
"exists": true,
|
||||
"models": {
|
||||
"models--Qdrant--bge-small-zh-v1.5": {
|
||||
"files": 13,
|
||||
"bytes": 190444780
|
||||
},
|
||||
"models--Qdrant--bm25": {
|
||||
"files": 39,
|
||||
"bytes": 56247
|
||||
}
|
||||
},
|
||||
"default_cache_dir": "/home/xiaomo/.cache/fastembed",
|
||||
"default_cache_exists": false,
|
||||
"release_note": "真实 mem0 模式把 fastembed cache_dir 指向发布实例数据目录内的该缓存拷贝;本次零下载、不推理"
|
||||
},
|
||||
"pip_2622_event": {
|
||||
"claim_under_review": "HEL-895 seq48–51:uv pip install --offline pip 失败后去掉 --offline 安装 pip 26.2.2 成功;前卡日志仅存尾两行",
|
||||
"installed_into": "/home/xiaomo/multica_workspaces/hello-af23464d222e/hel-895-0261e950b9c2/workdir/CyberGril/.venv311/lib/python3.11/site-packages/pip-26.2.2.dist-info",
|
||||
"installer": "uv",
|
||||
"uv_cache_entry_created": "2026-10-27T02:10:04.960958",
|
||||
"uv_http_cache_created": "2026-10-27T02:10:04.972959",
|
||||
"recorded_source_url": "https://files.pythonhosted.org/packages/3f/06/3e4420302363fbb71be3c7f35ce042f54bfca330e3e66b3a2e3c4cca579f/pip-26.2.2-py3-none-any.whl",
|
||||
"recorded_sha256": "fd7f4dfa8190e014013b9f08f3e973f4e4c26ffd179a204895533a7254813a70",
|
||||
"other_new_cache_entries_in_window": [],
|
||||
"verdict": "勘误成立:uv 缓存中 pip-26.2.2 wheel 条目创建于 2026-10-27 02:10:04 +0800(HEL-895 运行窗口内),来源 files.pythonhosted.org,且是该窗口唯一新增缓存条目——该步发生了网络获取,前卡『零下载』对此步不成立;requirements.lock 装机同期未产生任何新缓存条目(全部命中既有缓存)。字节级『完整下载 vs 条件请求』无法由缓存取证区分,按保守口径记为下载。"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
# HEL-879 rework: real-SDK check regenerated from THIS head's voice sources
|
||||
# head: 78a5cfd8d75e3cfd00c60dc5c3592eb08cc757a1
|
||||
# run: 2026-10-26T20:16:05Z, .12 /opt/voice-agent/agent/venv/bin/python (livekit-agents 1.8.8), stdin-only, zero writes zero network, no service touched
|
||||
# generator: scripts/gen_hel877_sdk_check.py (10 checks; #9/#10 new: worker callback path on real SpeechHandle/SpeechCreatedEvent; assistant_interim seam through real LLMStream)
|
||||
|
||||
HEL-877/879 real-SDK check on livekit-agents 1.8.8: ALL PASS
|
||||
OK CyberGrillLLM/ChatApiLLMStream subclass real livekit-agents 1.8.8 LLM/LLMStream
|
||||
OK latest_user_text reads a real ChatContext (items/role/text_content)
|
||||
OK fake-SSE turn through real LLMStream emits ChatChunks, final text and receipt
|
||||
OK chat.error phi is spoken verbatim via ChatChunk and carries no receipt
|
||||
OK mint_token claims byte-parity with livekit.api.AccessToken (video/iss/sub/keys)
|
||||
OK mint_server_token matches SDK no-grant auth header claims
|
||||
OK worker.py SDK surface (SpeechHandle, UserInputTranscribedEvent.is_final) present
|
||||
OK barge-in task cancel closes the in-flight HTTP stream immediately
|
||||
OK worker callback path on real SpeechHandle/SpeechCreatedEvent: no-generation handle discards, next turn keeps its own stream (explicit binding)
|
||||
OK assistant_interim seam: SSE deltas through real LLMStream feed her incremental subtitle payloads (replace semantics, reset works)
|
||||
@@ -0,0 +1,9 @@
|
||||
# HEL-896 · 固定 SDK 离线余缺审计摘要(只读)
|
||||
|
||||
- 闭包 55 项,产品 3.11 venv 缺 41 项:纯 Python 28 项、原生扩展 13 项(charset-normalizer, greenlet, grpcio, hf-xet, jiter, mmh3, numpy, onnxruntime, pillow, protobuf, py-rust-stemmers, sqlalchemy, tokenizers)。
|
||||
- 三个顶层包 WHEEL 均 py3-none-any(纯 Python,可跨 3.10/3.11)。
|
||||
- mem0ai 固定源码身份:tarball SHA256 一致(9dcef9303ebcec116eec6739f01b8b35bd24459de6a569686b4d19b9412dda23);索引同名 wheel 不作数;hel857 构建过的 wheel(698284b6083a…)在临时缓存、未持久。
|
||||
- 当前缓存可直接复用的缺项 wheel:['greenlet', 'pillow', 'truststore']。
|
||||
- 其余缺项(纯 Python wheel 与 cp311 原生 wheel)由发布卡按 deploy/hel874-release.md §4 获授权后下载并 sha256 留证;缺项不阻塞其余发布工作。
|
||||
- fastembed 模型缓存实测:{"models--Qdrant--bge-small-zh-v1.5": {"files": 13, "bytes": 190444780}, "models--Qdrant--bm25": {"files": 39, "bytes": 56247}}(hel857-data/fastembed-cache,随发布实例落位,零下载)。
|
||||
- pip 26.2.2 事件:勘误成立:uv 缓存中 pip-26.2.2 wheel 条目创建于 2026-10-27 02:10:04 +0800(HEL-895 运行窗口内),来源 files.pythonhosted.org,且是该窗口唯一新增缓存条目——该步发生了网络获取,前卡『零下载』对此步不成立;requirements.lock 装机同期未产生任何新缓存条目(全部命中既有缓存)。字节级『完整下载 vs 条件请求』无法由缓存取证区分,按保守口径记为下载。
|
||||
@@ -0,0 +1,16 @@
|
||||
/opt/voice-agent/agent/venv/lib/python3.12/site-packages/jwt/api_jwt.py:149: InsecureKeyLengthWarning: The HMAC key is 6 bytes long, which is below the minimum recommended length of 32 bytes for SHA256. See RFC 7518 Section 3.2.
|
||||
return self._jws.encode(
|
||||
/opt/voice-agent/agent/venv/lib/python3.12/site-packages/jwt/api_jwt.py:370: InsecureKeyLengthWarning: The HMAC key is 6 bytes long, which is below the minimum recommended length of 32 bytes for SHA256. See RFC 7518 Section 3.2.
|
||||
decoded = self.decode_complete(
|
||||
HEL-877/879 real-SDK check on livekit-agents 1.8.8: ALL PASS
|
||||
OK CyberGrillLLM/ChatApiLLMStream subclass real livekit-agents 1.8.8 LLM/LLMStream
|
||||
OK latest_user_text reads a real ChatContext (items/role/text_content)
|
||||
OK fake-SSE turn through real LLMStream emits ChatChunks, final text and receipt
|
||||
OK chat.error phi is spoken verbatim via ChatChunk and carries no receipt
|
||||
OK mint_token claims byte-parity with livekit.api.AccessToken (video/iss/sub/keys)
|
||||
OK mint_server_token matches SDK no-grant auth header claims
|
||||
OK worker.py SDK surface (SpeechHandle, UserInputTranscribedEvent.is_final) present
|
||||
OK barge-in task cancel closes the in-flight HTTP stream immediately
|
||||
OK installed-SDK source verified: speech tasks set agents_speech_handle around the pipeline; speech_created precedes the task; llm_node calls llm.chat inside it
|
||||
OK ACTUAL worker module loaded; its registered callbacks driven on a real AgentSession: both-queued delayed generations bind exactly (manager interleaving), say never steals a stream, unattributed fails closed, interrupt cancels without final/receipt
|
||||
OK assistant_interim seam: real LLMStream deltas feed per-speech_id v2 payloads (replace semantics); unattributed streams feed nothing
|
||||
@@ -0,0 +1,15 @@
|
||||
HEL-877/879 real-SDK check on livekit-agents 1.8.8: ALL PASS
|
||||
OK CyberGrillLLM/ChatApiLLMStream subclass real livekit-agents 1.8.8 LLM/LLMStream
|
||||
OK latest_user_text reads a real ChatContext (items/role/text_content)
|
||||
OK fake-SSE turn through real LLMStream emits ChatChunks, final text and receipt
|
||||
OK chat.error phi is spoken verbatim via ChatChunk and carries no receipt
|
||||
OK mint_token claims byte-parity with livekit.api.AccessToken (video/iss/sub/keys)
|
||||
OK mint_server_token matches SDK no-grant auth header claims
|
||||
OK worker.py SDK surface (SpeechHandle, UserInputTranscribedEvent.is_final) present
|
||||
OK barge-in task cancel closes the in-flight HTTP stream immediately
|
||||
OK installed-SDK source verified: speech tasks set agents_speech_handle around the pipeline; speech_created precedes the task; llm_node calls llm.chat inside it
|
||||
OK ACTUAL worker module loaded; its registered callbacks driven on a real AgentSession: both-queued delayed generations bind exactly (manager interleaving), say never steals a stream, unattributed fails closed, interrupt cancels without final/receipt
|
||||
OK assistant_interim seam: real LLMStream deltas feed per-speech_id v2 payloads (replace semantics); unattributed streams feed nothing
|
||||
OK speak_proactive_row publishes proactive_start while the real SpeechHandle is still playing (sync-say shape), end/cancel on the handle's done callback
|
||||
OK interrupted proactive row emits proactive_cancel(reason=interrupted), never proactive_end
|
||||
OK incomplete/no-receipt attributed stream: actual worker callbacks emit turn_start -> turn_cancel only, no assistant_final, no ack
|
||||
@@ -0,0 +1,9 @@
|
||||
{"v": 2, "seq": 1, "kind": "turn_start", "role": "assistant", "text": "", "speech_id": "speech_cut"}
|
||||
{"v": 2, "seq": 2, "kind": "assistant_interim", "role": "assistant", "text": "我正想跟你说,今天下午", "speech_id": "speech_cut"}
|
||||
{"v": 2, "seq": 3, "kind": "turn_cancel", "role": "assistant", "text": "", "speech_id": "speech_cut", "reason": "interrupted"}
|
||||
{"v": 2, "seq": 4, "kind": "interim", "role": "user", "text": "等一下"}
|
||||
{"v": 2, "seq": 5, "kind": "user_final", "role": "user", "text": "等一下,先听我说。"}
|
||||
{"v": 2, "seq": 6, "kind": "turn_start", "role": "assistant", "text": "", "speech_id": "speech_next"}
|
||||
{"v": 2, "seq": 7, "kind": "assistant_interim", "role": "assistant", "text": "好,你先说。", "speech_id": "speech_next"}
|
||||
{"v": 2, "seq": 8, "kind": "assistant_final", "role": "assistant", "text": "好,你先说。", "speech_id": "speech_next", "turn_id": "0e2f-demo-next"}
|
||||
{"v": 2, "seq": 9, "kind": "turn_end", "role": "assistant", "text": "", "speech_id": "speech_next", "turn_id": "0e2f-demo-next"}
|
||||
@@ -0,0 +1,7 @@
|
||||
{"v": 2, "seq": 1, "kind": "interim", "role": "user", "text": "你在听的"}
|
||||
{"v": 2, "seq": 2, "kind": "user_final", "role": "user", "text": "你在听吗?"}
|
||||
{"v": 2, "seq": 3, "kind": "turn_start", "role": "assistant", "text": "", "speech_id": "speech_normal"}
|
||||
{"v": 2, "seq": 4, "kind": "assistant_interim", "role": "assistant", "text": "在听呢,", "speech_id": "speech_normal"}
|
||||
{"v": 2, "seq": 5, "kind": "assistant_interim", "role": "assistant", "text": "在听呢,在听呢,你刚才说到一半的那件事我还在想。", "speech_id": "speech_normal"}
|
||||
{"v": 2, "seq": 6, "kind": "assistant_final", "role": "assistant", "text": "在听呢,你刚才说到一半的那件事我还在想。", "speech_id": "speech_normal", "turn_id": "0e2f-demo-turn"}
|
||||
{"v": 2, "seq": 7, "kind": "turn_end", "role": "assistant", "text": "", "speech_id": "speech_normal", "turn_id": "0e2f-demo-turn"}
|
||||
@@ -0,0 +1,4 @@
|
||||
{"v": 2, "seq": 1, "kind": "proactive_start", "role": "assistant", "text": "我看到一句很适合现在的话,先念给你听。", "speech_id": "speech_pro1", "message_id": 17}
|
||||
{"v": 2, "seq": 2, "kind": "proactive_end", "role": "assistant", "text": "", "speech_id": "speech_pro1", "message_id": 17}
|
||||
{"v": 2, "seq": 3, "kind": "proactive_start", "role": "assistant", "text": "还有一件事想告诉你——", "speech_id": "speech_pro2", "message_id": 18}
|
||||
{"v": 2, "seq": 4, "kind": "proactive_cancel", "role": "assistant", "text": "", "speech_id": "speech_pro2", "message_id": 18, "reason": "interrupted"}
|
||||
@@ -0,0 +1 @@
|
||||
{"remote_delete_count_after_ttl": 1, "expired_but_registered": false, "cleanup_owner_present": false}
|
||||
@@ -0,0 +1 @@
|
||||
{"remote_delete_count_after_ttl": 0, "expired_but_registered": true, "cleanup_owner_present": false}
|
||||
@@ -0,0 +1 @@
|
||||
{"proactive_before_playout_finishes": {"handle_done": false, "events": ["proactive_start"]}, "proactive_after_playout_finishes": ["proactive_start", "proactive_end"], "proactive_payload_fields": {"v": 2, "kind": "proactive_start", "role": "assistant", "text": "offline sample", "speech_id": "speech_f28fdeb15e01", "message_id": 7}, "no_receipt_incomplete_actual_worker_events": ["turn_start", "turn_cancel"], "no_receipt_incomplete_confirmed": [], "complete_with_receipt_actual_worker_events": ["turn_start", "assistant_final", "turn_end"], "complete_with_receipt_confirmed": ["ok-turn"]}
|
||||
@@ -0,0 +1 @@
|
||||
{"proactive_before_playout_finishes": {"handle_done": false, "events": []}, "proactive_after_playout_finishes": ["proactive_start", "proactive_end"], "proactive_payload_fields": {"v": 2, "kind": "proactive_start", "role": "assistant", "text": "offline sample", "speech_id": "speech_2880d36ea013", "message_id": 7}, "no_receipt_incomplete_actual_worker_events": ["turn_start", "assistant_final", "turn_end"], "no_receipt_incomplete_confirmed": [], "complete_with_receipt_actual_worker_events": ["turn_start", "assistant_final", "turn_end"], "complete_with_receipt_confirmed": ["ok-turn"]}
|
||||
@@ -0,0 +1,37 @@
|
||||
# HEL-879 契约核准后 3 处实现时机收口(2026-10-27)
|
||||
|
||||
核对对象:`hel-879-assembly @ 3228b1e0d7f822b7030f945e285eac74126771aa`(总管《HEL-879-契约核准与接续.md》)。
|
||||
本轮只修 3 处实现与已定契约 v2 不一致的问题:不改 `v` 信封字段、不改事件种类、不动 `web/src`、不重做已过绑定/备份/预算。
|
||||
|
||||
## 修前复现(全部先复现失败,与总管证据一致)
|
||||
|
||||
| # | 发现 | 修前证据 |
|
||||
|---|------|----------|
|
||||
| 1 | `open_session` 只在 `await create_dispatch` 前 kick;建房真实让出事件循环后 cleaner 空转退出,注册后无人再观察截止时间 | `delayed-dispatch-before.json`:`{"remote_delete_count_after_ttl": 0, "expired_but_registered": true, "cleanup_owner_present": false}`(与总管 delayed-dispatch.json 逐字段一致) |
|
||||
| 2 | `speak_proactive_row` 旧写法 `handle = await session.say(...)`;真实 SDK `say` 为同步函数、`await handle`=等整段播完 → 播完才发 proactive_start | `sdk-probe-before.json`:`proactive_before_playout_finishes.events=[]`,播完后才 `["proactive_start","proactive_end"]` |
|
||||
| 3 | `_after_playout` 先按 `stream.text` 发 final/end 再查回执;注入 text 非空、completed=False、receipt=None 的确切归属流 → `turn_start→assistant_final→turn_end`,与 v2「无完整同轮回执只 cancel」相反 | 同上:`no_receipt_incomplete_actual_worker_events=["turn_start","assistant_final","turn_end"]`(实际 worker `bind_voice_session` 回调路径,真实 AgentSession/SpeechHandle) |
|
||||
|
||||
新增专项测试在**未修复代码上先跑失败**(repro-first):
|
||||
`tests/test_voice_rework_hel879.py::test_open_session_with_real_dispatch_yield_re_kicks_cleanup`、
|
||||
`::test_second_registration_wakes_a_sleeping_cleaner_for_earlier_deadline` → 修前 2 failed / 修后 2 passed。
|
||||
|
||||
## 修复(精确小修)
|
||||
|
||||
1. `src/cybergril/voice/session.py` `open_session`:注册成功并 `_persist_state()` 之后**重新 `_kick_cleanup()`**——建房 await 期间旧 cleaner 可能已因「无可观察对象」退出,新截止时间需要新的所有者;自动截止、共享上限、重启补偿、有界放弃全部保留。测试用**真正让出事件循环**的建房替身(`asyncio.sleep(0.02)`),不再只用立即返回的 MockTransport 替身。
|
||||
2. `src/cybergril/voice/worker.py` `speak_proactive_row`:先取 handle(`iscoroutine` 只解包 await 型替身——真实 SpeechHandle 自身可 await,不能误等)、**立即**发布 `proactive_start`、注册该 handle 的 `proactive_end/proactive_cancel`,再按需等待这一条播完(逐条顺序念保留)。
|
||||
3. `src/cybergril/voice/worker.py` `_after_playout`:`assistant_final` 前置必要门——流 `completed` 且 `should_ack`(合法同轮 receipt、非旧 epoch)才 `finish`+`confirm`;未完整/无回执/旧 epoch 一律只 `turn_cancel`(reason=incomplete/no-receipt),**绝不先发 final 再决定不确认**;φ/打断/失败/无归属 fail-closed 原样保留,完整+合法回执路径的 final 与 ack 均保留。
|
||||
|
||||
## 修后验证
|
||||
|
||||
- 本地:`delayed-dispatch-after.json`:`{"remote_delete_count_after_ttl": 1, "expired_but_registered": false, "cleanup_owner_present": false}`(cleaner 在全部结清后按设计自行退出,无悬空协程)。
|
||||
- `.12` 真 SDK(stdin 嵌入当前源码,零写入零网络,`/opt/voice-agent/agent/venv` livekit-agents 1.8.8)`sdk-probe-after.json`:
|
||||
- `proactive_before_playout_finishes={"handle_done": false, "events": ["proactive_start"]}`(播放中即可见 start);
|
||||
- 播完 `["proactive_start","proactive_end"]`,字段 `v/kind/role/text/speech_id/message_id` 与 v2 完全一致;
|
||||
- `no_receipt_incomplete=["turn_start","turn_cancel"]`、`confirmed=[]`;
|
||||
- 完整+合法回执路径 `["turn_start","assistant_final","turn_end"]` + ack 保留。
|
||||
- 真SDK回归并入常驻检查 `scripts/gen_hel877_sdk_check.py`(**14/14 ALL PASS**,`../sdk-check-hel879-timing.log`):新增「主动播报时机」「主动播报打断只有 cancel」「无回执不 final」三负例,均驱动实际 worker 模块注册的真实回调。
|
||||
- 产品套件:pytest **352/352**(3 次连跑);ruff(src/tests/tools) **0 错**;`verify_hel877_voice_chain.py` **8/8**;需求检查 **4/4**(origin/main 与 c121c42 各带/不带 handoff-HEL-879.json)。字幕样例 `subtitle-samples/` 与 v2 契约文档无需再生成(字段与生命周期未变)。
|
||||
|
||||
## 边界
|
||||
|
||||
零真实 LLM/嵌入/ASR/TTS/麦克风;.12 仅 SSH stdin 执行只读检查(零写入零网络,stderr 仅既有 jwt 弱密钥告警);零下载零安装;未部署、未合并;PR#11 与 `hel-870-assembly` 未动;权威账/冻结/共享服务/队员配置未碰;真实 cap 仍 0。R5 真机、完整 CG-011、R6/R7 继续承接,无需求变更(v1.11/60 项)。
|
||||
@@ -0,0 +1,60 @@
|
||||
# HEL-879 · 统一候选一次复审收口(总工,2026-10-27)
|
||||
|
||||
> 范围:按总管 2026-10-27 交接,把 HEL-898 三项返修的隔离保全候选
|
||||
> (`origin/hel-898-preserved` @ `18aef2a`:9254c17 = 作者 12 文件逐字节保全,
|
||||
> 父 b0dcb17;18aef2a = 仅记录/证据)**正常快进纳入** `hel-879-assembly`,
|
||||
> 对这三项做最后一次复审收口。不开新审核串、不重审已过后台/预算/备份/receipt
|
||||
> 时机内核、不替原作者改视觉。零真实调用、零下载/安装/部署/合并,真实 cap 仍 0。
|
||||
|
||||
## 一、整合事实
|
||||
|
||||
- 快进前远端:`hel-879-assembly` @ `b0dcb17`(11fd0e2/9756db3/b0dcb17 材料成果
|
||||
全保留,未退回 f92a86f)。快进后 head **`18aef2a`**,无冲突、无强推;
|
||||
PR#11 与 `hel-870-assembly`(c121c42)未动。
|
||||
- 9254c17 恰为 12 文件(`web/src` 6 + `web/tests` 5 + `handoff-HEL-898.json`),
|
||||
与总管 preservation-review.md 记录的作者交付逐字节保全一致;18aef2a 仅新增
|
||||
`docs/rework/hel898/f92a86f-rework/` 记录与证据(31 文件)。
|
||||
- **b0dcb17→18aef2a 对 `src/`、`tests/`、`tools/`、`deploy/` 零 diff**
|
||||
(实跑 `git diff --stat` 为空)——后端/协议/预算/备份/receipt 时机零改动成立。
|
||||
|
||||
## 二、三项返修复审(源码级 + 测试级,均通过)
|
||||
|
||||
1. **agent 离场僵尸界面/麦克风不停**(`web/src/voice/livekit.ts` +
|
||||
`session.ts`):transport 按 identity 记录已见 agent(连接事件与初始
|
||||
remoteParticipants 扫描都入 Set);`ParticipantDisconnected` 仅当离场者是
|
||||
该 agent 且房内再无其它 agent 时触发 `agentLeft`;控制器走**既有** `fail()`
|
||||
路径(mic 先停 → room 关闭 → 服务器 DELETE,离线欠账照常补发)。普通参与者
|
||||
离场、旧房间迟到事件、自己挂断、重复第二 worker 均不误触发——
|
||||
`web/tests/hel898_agent_left.test.ts` 7 例(含 DELETE 欠账重发与 stale 负例)。
|
||||
2. **closed 64 挤出复活**(`session.ts`):退休 speech 集合由 64 上限环形数组
|
||||
改为**每通话 `Set<string>` 全程保留、随代次整体释放**;seq 高水位门不变,
|
||||
未以放宽乱序保护换修复。f92a86f 审核所记 DOCUMENTED GAP 就此关闭。
|
||||
3. **播放中短回复被压到 final**(`reading.ts` + `lineStage.ts` +
|
||||
`ChatPanel.tsx` + `voiceLine`):语音打开的她的行改 `live: 'speaking'`,
|
||||
末块只显示**已成句**部分(`said()` 截到句末标点+引号括号),文字 generating
|
||||
原持有规则不变;同键行 `grow()` 原位增长(保留 DOM/已演字,非续写才整段
|
||||
置换),签名纳入语音行文本驱动重呈现;阅读时钟对增长行只增不减时长。
|
||||
落库接替沿用同键(turn:mi:index),不重播、不重复演字。
|
||||
|
||||
## 三、独立检查(针对本次真实变更,均实跑)
|
||||
|
||||
- `web` vitest **118/118**(10 文件,含 hel898_agent_left 7 例、hel879_frames
|
||||
10 例、voice 45 例);typecheck 0 错;lint 0 错/1 既有 fullButton ref 警告;
|
||||
build 通过(CSS 哈希 `index-BpZaybfD.css` 与既认可视觉一致,JS 因本次修复
|
||||
变更为 `index-C23OdPgW.js`,属预期)。
|
||||
- 需求结构检查 3/3 通过:`--base-ref origin/main`、`--base-ref b0dcb17`、
|
||||
`--base-ref b0dcb17 --handoff docs/requirements/handoff-HEL-898.json`;
|
||||
本轮结束后再以 origin/main ± 本卡 handoff 复跑(见提交说明)。
|
||||
- 浏览器统一回放(两主题电脑/手机、减少动态、worker 实际录制帧、8 段 WebM)
|
||||
**不重复复跑**:总管已在 18aef2a 记录 53/53 与媒体证据
|
||||
(manager-checks/browser.log),本轮零安装策略下不重开。
|
||||
|
||||
## 四、结论与边界
|
||||
|
||||
- 三项返修**离线通过**,与后台 v2 契约无冲突;统一候选当前准确 head
|
||||
`18aef2a`(本轮复审与 D1 试听材料另追加提交,见分支历史)。
|
||||
- 仍不冒充的部分:以上全部是假 LiveKit/假媒体的离线回放与单测;真实
|
||||
WebRTC/麦克风/ASR/TTS、三轮/1 秒打断停声停麦、可信 HTTPS+WSS 设备路径、
|
||||
iOS/Android、API 重启真实释放**均未测**,待主卡批准后 R5 真机窗口执行。
|
||||
完整 CG-011 会话中主动表达、完整 mem0 统一体验/R6/R7 继续承接。
|
||||
- v1.11/60 项无变更;冻结账/权威账未写;既有五实例与共享服务零接触。
|
||||
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"sdk": {
|
||||
"livekit_agents": "1.8.8",
|
||||
"livekit_api": "1.2.1"
|
||||
},
|
||||
"source": "actual fc905fe+fb7ea84 worker driven on .12 real SDK (livekit-agents 1.8.8, livekit-api 1.2.1) via SSH stdin, zero network/writes",
|
||||
"scenarios": {
|
||||
"normal": {
|
||||
"kinds": [
|
||||
"interim",
|
||||
"user_final",
|
||||
"turn_start",
|
||||
"assistant_interim",
|
||||
"assistant_interim",
|
||||
"assistant_interim",
|
||||
"assistant_final",
|
||||
"turn_end"
|
||||
],
|
||||
"frames": 8,
|
||||
"acks": [
|
||||
"382c41d9-0d72-433e-b370-f838fa5d0bd0"
|
||||
],
|
||||
"turn_id": "382c41d9-0d72-433e-b370-f838fa5d0bd0"
|
||||
},
|
||||
"interrupt": {
|
||||
"kinds": [
|
||||
"user_final",
|
||||
"turn_start",
|
||||
"assistant_interim",
|
||||
"assistant_interim",
|
||||
"turn_cancel",
|
||||
"user_final",
|
||||
"turn_start",
|
||||
"assistant_interim",
|
||||
"assistant_interim",
|
||||
"assistant_final",
|
||||
"turn_end"
|
||||
],
|
||||
"frames": 11,
|
||||
"acks": [
|
||||
"edbcb837-f19f-47e7-8d5c-057010da43eb"
|
||||
],
|
||||
"turn_ids": {
|
||||
"cut": "09d05c0f-3058-4ff8-a56e-4e94bd17d7b7",
|
||||
"next": "edbcb837-f19f-47e7-8d5c-057010da43eb"
|
||||
}
|
||||
},
|
||||
"phi": {
|
||||
"kinds": [
|
||||
"user_final",
|
||||
"turn_start",
|
||||
"assistant_interim",
|
||||
"assistant_interim",
|
||||
"assistant_interim",
|
||||
"error",
|
||||
"turn_cancel"
|
||||
],
|
||||
"frames": 7,
|
||||
"acks": [],
|
||||
"turn_id": "31e70e52-1471-4e50-ac49-cce89979a9bf"
|
||||
},
|
||||
"no_receipt": {
|
||||
"kinds": [
|
||||
"user_final",
|
||||
"turn_start",
|
||||
"assistant_interim",
|
||||
"assistant_interim",
|
||||
"turn_cancel"
|
||||
],
|
||||
"frames": 5,
|
||||
"acks": [],
|
||||
"turn_id": "36d160e3-e365-46ff-ad57-c2878c00720f"
|
||||
},
|
||||
"proactive": {
|
||||
"kinds": [
|
||||
"proactive_start",
|
||||
"proactive_end",
|
||||
"proactive_start",
|
||||
"proactive_cancel"
|
||||
],
|
||||
"frames": 4,
|
||||
"start_while_playing": true
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
需求结构检查通过:60项;来源和覆盖完整。仍须人工核对授权语义与实际体验。
|
||||
@@ -0,0 +1 @@
|
||||
需求结构检查通过:60项;来源和覆盖完整。仍须人工核对授权语义与实际体验。
|
||||
@@ -0,0 +1 @@
|
||||
需求结构检查通过:60项;来源和覆盖完整。仍须人工核对授权语义与实际体验。
|
||||
@@ -0,0 +1 @@
|
||||
需求结构检查通过:60项;来源和覆盖完整。仍须人工核对授权语义与实际体验。
|
||||
@@ -0,0 +1,97 @@
|
||||
# R5 测试包 v2 · .12 只读实测证据(2026-10-27)
|
||||
|
||||
> 性质:本轮材料返修的事实底稿。全部为 SSH 只读命令与输出摘录(零写入、零服务变更、
|
||||
> 不发任何模型/嵌入/ASR/TTS 请求);涉及凭据的值一律以 `<REDACTED>` 脱敏,不落仓库。
|
||||
> 命令在 .12(root@192.168.200.12)执行;时间 2026-10-27(UTC 时段见 issue)。
|
||||
|
||||
## E1 · 端口监听(`ss -tlnp` 摘录)
|
||||
|
||||
监听中(与 R5 相关/受保护):
|
||||
|
||||
| 端口 | 进程 | 说明 |
|
||||
| --- | --- | --- |
|
||||
| 7880、7881 | livekit-server (pid 219106, docker `voice-livekit`, host 网络) | 7880=HTTP/WS 信令;7881=WebRTC TCP 回落口 |
|
||||
| 10095 | docker-proxy(funasr-runtime-sdk-online-cpu-0.1.13) | 流式 ASR |
|
||||
| 8090 | python (pid 2136834, `/opt/voice-agent/agent/venv/bin/python server.py`, cwd `/opt/voice-agent/web`) | 语音演示页(https-only,见 E3) |
|
||||
| 8081 | python (pid 451883, `venv/bin/python agent.py start`, cwd `/opt/voice-agent/agent`) | 通用 cascade worker |
|
||||
| 8300/8310/8320/8340/8350 | 各既有 CyberGril 实例 | 受保护,不触碰 |
|
||||
|
||||
**空闲(无监听)**:8360、8361、8363、8082、9880(TTS 停机中)。
|
||||
|
||||
## E2 · LiveKit docker 无 TLS 配置(`docker inspect` + `docker-compose.yml`)
|
||||
|
||||
- `voice-livekit`:`command: --bind 0.0.0.0`,`network_mode: host`,无任何证书挂载
|
||||
(Mounts=[]),环境仅 `LIVEKIT_KEYS`(值脱敏)。
|
||||
- 探测:`curl http://127.0.0.1:7880` → **200**(纯 HTTP 存活);
|
||||
`curl -k https://127.0.0.1:7881/` 与 `curl http://127.0.0.1:7881/` → 均失败
|
||||
(7881 不是 HTTP(S) 端点,是 WebRTC TCP 回落口,不能当 WSS 信令用)。
|
||||
|
||||
## E3 · 8090 演示页现状
|
||||
|
||||
- `https://127.0.0.1:8090/` → 200;`http://127.0.0.1:8090/` → 失败(https-only)。
|
||||
- 证书:`CN = minicpmo45-dev`,**无 subjectAltName 扩展**,notAfter 2027-02-11。
|
||||
- `server.py:66`:`LIVEKIT_URL = "ws://192.168.200.12:7880"` —— 页面 `/api/token`
|
||||
把该 ws:// 地址发给浏览器 `room.connect(url, token)`。https 页面连 ws:// 属
|
||||
**混合内容**,库存浏览器默认拦截;**没有任何证据**表明该页在标准浏览器走通过
|
||||
媒体链路。旧材料「自签一次点击同时覆盖 LiveKit WSS 7880」不成立,已删除。
|
||||
- 面板功能(index.html/server.py 实读):音色列表 `GET /api/voices`、切换
|
||||
`POST /api/voice`(写共享 `voice_state.json`)、克隆上传 `POST /api/voices/upload`
|
||||
(写共享 `voices.json` + TTS 热加载)、删除。**没有既有音色的试听播放功能**
|
||||
(`vPreview` 仅用于克隆上传的自选文件)。
|
||||
|
||||
## E4 · 通用 worker 依赖 7880 保持明文(改 TLS 的破坏面)
|
||||
|
||||
`/opt/voice-agent/agent/.env`:`LIVEKIT_URL=ws://127.0.0.1:7880`(另有
|
||||
LIVEKIT_API_KEY/SECRET,值脱敏)。**7880 一旦改 TLS-only 即断通用 worker 与
|
||||
8090 演示,禁止作为本卡路线。**
|
||||
|
||||
## E5 · .12 上没有已装 mem0 的产品 venv(「零真缺」不能笼统写)
|
||||
|
||||
- 8310(`/opt/cybergril-api/current/.venv`,r2-20261022)与 8350
|
||||
(`/opt/cybergril-hel835/current/.venv`)抽查:`python -c "import mem0"` 均
|
||||
`ModuleNotFoundError`;两者均为 **Python 3.12.3**(系统 python 建 venv)。
|
||||
- 8320/8340 同构部署(各自 `current/.venv`),未逐一导入验证。
|
||||
- 结论:所抽查的两处不能提供已装 mem0 闭包,不能据抽查推断 .12 所有实例均已
|
||||
验证不存在。完整统一体验依赖分类以本仓库
|
||||
`docs/rework/hel879/release-artifacts.json`(总管已核准)为准。
|
||||
|
||||
## E6 · worker venv 与 TTS 底座(语音专项链已备)
|
||||
|
||||
- `/opt/voice-agent/agent/venv`:`import livekit, livekit.agents` 成功,
|
||||
livekit-agents **1.8.8**(venv 为 python3.12,worker 不依赖产品 mem0 闭包,
|
||||
经 HTTP 调统一 API)。
|
||||
- CosyVoice:`/opt/voice-agent/cosyvoice/server.py` 实读——路由 `/health`、`/tts`
|
||||
存在;`uvicorn.run(host="0.0.0.0", port=9880)`;当前 9880 无监听(停机待授权
|
||||
重启);权重在位(`/opt/models/CosyVoice3-0.5B-2512`,约 9.1GB)。
|
||||
|
||||
## E7 · 音色真实清单(voices.json 实读)
|
||||
|
||||
- 11 个 ID:`bailu, bajie, default, female_soft, haimianbaobao, jiaojiao,
|
||||
male_warm, nezha, rain, sunwukong, xiaoyun`;每项含 `prompt_wav` 指向
|
||||
`voice_samples/<id>.wav`(zero-shot 参考音频,即该音色的音色来源录音,
|
||||
bailu.wav 1.77MB 等,目录实存)。
|
||||
- 共享演示当前 `voice_state.json` = `{"voice": "rain"}` —— 是通用演示状态,
|
||||
**不是本用户的选择**,不作为本用户音色依据。
|
||||
|
||||
## E8 · GPU / 内存 / 磁盘(`nvidia-smi` / `free` / `df`)
|
||||
|
||||
- RTX 5090D:总量 32607 MiB,已用 1558 MiB,**空闲 30520 MiB**(ComfyUI 仍处
|
||||
已授权暂停;GPU 进程仅 gnome-remote-desktop 996MiB)→ CosyVoice 常驻约
|
||||
5.6GB 无障碍。
|
||||
- 内存 94GB(可用 83GB);`/` 916GB 用 16%,余 735GB。
|
||||
|
||||
## E9 · /opt 无冲突目录
|
||||
|
||||
`/opt` 现有 `cybergril-api / cybergril-data / cybergril-hel822 / cybergril-hel829 /
|
||||
cybergril-hel835 / cybergril-ops / cybergril-s1 / voice-agent / models` 等;
|
||||
**无 `voice-agent-cybergril`、无 `cybergril-voice-certs`**(新建不冲突)。
|
||||
|
||||
## E10 · 预算硬闸语义(本仓库代码,非 .12)
|
||||
|
||||
`src/cybergril/think/budget.py` `acquire()`:真实 provider 出口**发送前**原子
|
||||
预占(类别日顶 `daily_requests` + 一次性总量 `total_requests` + `daily_tokens` +
|
||||
`total_tokens` 同步检查,任一到顶抛 `BudgetStop`,持久化实现落在单个
|
||||
`BEGIN IMMEDIATE` 事务)。**失败/重试/打断/后台调用同样计数**——计数粒度是
|
||||
provider 调用,不是成功聊天行数。封账 `budget_sealed` 拒绝一切 acquire。
|
||||
语音轮经统一 `/api/chat` 走同一 dialogue 闸;`POST /api/voice/session` 建房
|
||||
**当前不在 budget 闸内**(如实列为操作侧上限+工程后续小项)。
|
||||
@@ -0,0 +1,223 @@
|
||||
# HEL-879 · R5 真机测试包 v2(供主卡拍板的集中材料,未执行)
|
||||
|
||||
> 性质:**准备材料**(v2 材料返修版,按总管 2026-10-27 四项返修清单重写)。零真实
|
||||
> 模型/嵌入/ASR/TTS/麦克风请求、零下载/安装/部署/合并、真实 cap=0。.12 全部事实为
|
||||
> 2026-10-27 只读实测,底稿与命令摘录见同目录 `r5-facts-20261027.md`(脱敏)。
|
||||
> 事实三级标注:**已证**(实测/代码实读)|**拟议**(材料备齐待批,未执行)|
|
||||
> **待真机**(须获批实测后才能写通过)。
|
||||
>
|
||||
> v2 勘误(相对 v1):①删「统一实例依赖零真缺/零下载」笼统结论,改两轨拆分(§1);
|
||||
> ②删「自签一次点击同时覆盖 LiveKit WSS 7880」——7880 现为纯 ws 且被共享服务依赖,
|
||||
> WSS 改由独立 8363 桥承担(§3);③预算 30 轮表改逐类计数位置+硬闸/操作停机拆分
|
||||
> (§6);④工程项(端口/目录/健康口)由工程核定(§10),不再交用户选择;D1 改实际
|
||||
> 音色清单+零合成试听方案(§4)。
|
||||
|
||||
## 1. 依赖两轨(不能混称「零真缺」)
|
||||
|
||||
### 1a. R5 语音专项(语音链本身)——**已证**零真缺、零下载
|
||||
|
||||
| 部件 | 状态 | 依据 |
|
||||
| --- | --- | --- |
|
||||
| LiveKit SFU | ✅ 运行中 .12:7880/7881 | 已证 7880 HTTP 200;**纯 ws 无 TLS**(E2) |
|
||||
| FunASR 流式 ASR | ✅ 运行中 .12:10095 | 已证监听(E1) |
|
||||
| worker 运行时 | ✅ 在位 `/opt/voice-agent/agent/venv` | 已证 import livekit-agents 1.8.8(py3.12;worker 经 HTTP 调统一 API,不依赖 mem0 闭包,E6) |
|
||||
| CosyVoice3 TTS | ⛔ 停机待重启授权 | 已证权重在位(约 9.1GB)、9880 无监听、`/health` `/tts` 路由存在(E6);重启=运维动作非下载 |
|
||||
| GPU/内存/磁盘 | ✅ 充足 | 已证空闲 30520MiB / 83GB / 735GB(E8) |
|
||||
| 统一 API 实例(8360) | ⛔ 待部署 | 部署物=本候选 head + 已过发布包 §2 全离线基础安装(requirements.lock 装机全部命中既有缓存,已证,见 sdk-audit) |
|
||||
|
||||
**语义边界(必须如实)**:本轨在 `semantic=stub` 下验收**语音链**——同一份档案数据、
|
||||
同一进程、同一把轮次锁,但**嵌入 0、语义记忆未激活**。本轨通过 ≠ 「同档案全记忆
|
||||
验收」;完整统一体验是 1b,两者分开批、分开验,互不冒充。
|
||||
|
||||
### 1b. 完整统一体验(真实 mem0 记忆)——41 项闭包,**真缺待授权**(已证分类)
|
||||
|
||||
- **已证范围**:.12 的 8310/8350 两个既有产品实例 venv 抽查均
|
||||
`ModuleNotFoundError`,且均为系统 3.12.3;8320/8340 未逐一验证,E5。
|
||||
不能据两处抽查声称所有实例均已验证,也没有可据此采用的已装 mem0 闭包——
|
||||
「零真缺」对完整体验**不成立**。
|
||||
- 分类(`docs/rework/hel879/release-artifacts.json`,总管已核准口径):
|
||||
- **已离线成品**:mem0ai 固定源码轮 `mem0ai-2.2.1-py3-none-any.whl`
|
||||
(sha256 `698284b6…20e9db`,352,586 B / 153 文件,源 tarball 与
|
||||
`deploy/mem0-stack.lock` 哈希一致;未安装任何位置)。
|
||||
- **缓存可复用**:greenlet 3.5.6(cp311)、pillow 12.3.0(cp311)、
|
||||
truststore 0.10.5(py3-none-any)——本机 uv wheels-v6/v7 实测命中。
|
||||
- **待准备 37 项**(26 纯 Python + 11 原生;原 28/13 分别扣除
|
||||
mem0ai、truststore 两项纯 Python 和 greenlet、pillow 两项原生):按当前闭包
|
||||
扣除已成品/可复用项的数量,尚不等于目标平台已解析完成的下载结果。需下载授权后按
|
||||
发布包 §4 第 3 步拉取,逐项 sha256 留证;**体积未下载不猜**,下载窗口逐项
|
||||
记录。hatchling 已离线解决(1.32.4 缓存),不再申请。
|
||||
- **fastembed 模型缓存**:已证在位 bge-small-zh-v1.5 190,444,780 B +
|
||||
bm25 56,247 B(artifacts 实测数;hel895 文档「约 92MB」与此不符,以
|
||||
artifacts 为准——已列勘误待修)。
|
||||
- 逐项版本/哈希:以 `release-artifacts.json` 与
|
||||
`docs/rework/hel879/sdk-audit/sdk-audit.json` 为准(不在本文件复制防漂移)。
|
||||
- 安装位置:统一实例自足 `.venv311`(uv 管 CPython 3.11.16,发布包 §2/§4 唯一
|
||||
入口);不混 .12 系统 3.12、不碰既有实例 venv。
|
||||
- 边界重申:不以关闭 mem0、改 stub、少测记忆默认缩减用户完整体验要求。
|
||||
|
||||
## 2. 资源现状(已证,2026-10-27)
|
||||
|
||||
GPU RTX 5090D 空闲 30520MiB(ComfyUI 仍处已授权暂停);内存 94GB/可用 83GB;
|
||||
盘 916GB/余 735GB。端口实测:8360/8361/8363/8082 **空闲**;受保护监听
|
||||
8300/8310/8320/8340/8350/8090/8081/7880/7881/10095 一律不动;9880 停机待授权。
|
||||
|
||||
## 3. 可信 HTTPS + WSS(D3)——已证 / 拟议 / 待真机
|
||||
|
||||
### 3.1 已证事实(为什么 v1 的说法必须撤回)
|
||||
|
||||
1. LiveKit 7880 = **纯 HTTP/WS**(docker 无证书挂载无 TLS 配置,E2);7881 监听
|
||||
但**不是 HTTP(S) 端点**(http/https 探测均失败),是 WebRTC TCP 回落口,
|
||||
**不能当 WSS 用**。
|
||||
2. 通用 worker 与 8090 演示都依赖 `ws://127.0.0.1:7880`/`ws://…:7880`(E4)——
|
||||
**7880 改 TLS 会破坏共享服务,禁止**。
|
||||
3. 8090 演示页 https-only(证书 `CN=minicpmo45-dev`、**无 SAN**、至 2027-02-11);
|
||||
它给浏览器发的就是 `ws://…:7880`(E3)——https 页连 ws 属**混合内容**,无证据
|
||||
表明曾在标准浏览器走通。旧句「自签一次点击同时覆盖页面 HTTPS 与 WSS 7880」
|
||||
**不成立,已删除**。
|
||||
4. `config/voice.yaml` 是部署本地文件(模板 `config/voice.example.yaml`),仓库内
|
||||
无该文件——v1 写法勘误。
|
||||
|
||||
### 3.2 拟议路线(材料已备齐,未执行;缺的就是这个 WSS 桥,如实列出)
|
||||
|
||||
- **新自签证书一张**:`openssl req -x509 … subjectAltName=IP:192.168.200.12`,
|
||||
存 `/opt/cybergril-voice-certs/`(600),同证书服务 8361 与 8363 两个端口。
|
||||
- **8361**:统一实例 HTTPS 入口(同进程双入口,runbook-hel877-voice §4.4;
|
||||
本地 18360/18361 已冒烟,.12 未执行——拟议)。
|
||||
- **8363(新增)**:TLS→明文 TCP 桥 `deploy/voice/wss_bridge.example.py`
|
||||
(asyncio+ssl 标准库零新依赖;本地冒烟 TLS1.3+字节穿透通过,见
|
||||
`wss-bridge-smoke.log`):`wss://192.168.200.12:8363` → `127.0.0.1:7880`。
|
||||
`voice.yaml` 的 `livekit_url` 改 `wss://192.168.200.12:8363`;
|
||||
`livekit_internal` 保持 `http://127.0.0.1:7880`。不动 LiveKit、通用 worker、
|
||||
8090(独立进程,回滚=停进程)。
|
||||
- WebRTC 媒体面(UDP/7881 TCP)不经桥,由 WebRTC 自带 DTLS/SRTP 加密、无需
|
||||
证书例外——协议性质说明,实际连通**待真机**。
|
||||
|
||||
### 3.3 每设备信任步骤(拟议;**分端口各一次**,不共享例外)
|
||||
|
||||
1. 打开 `https://192.168.200.12:8361` → 高级→继续(页面例外)。
|
||||
2. 打开 `https://192.168.200.12:8363` → 高级→继续(WSS 信令例外;该地址 GET
|
||||
返回 404/400 属预期,只看证书警告页点继续)。
|
||||
3. 允许麦克风。
|
||||
|
||||
- 两个实际端点分别打开并验证;不推断一个端点的例外必然覆盖另一个,也不把
|
||||
浏览器的例外缓存范围写成已实测事实。**不用** `--ignore-certificate-errors`、
|
||||
不装根证书、不改系统信任库(未授权,也不作为验收路径)。
|
||||
- **待真机**:iOS Safari「访问此网站」是否放行 wss、安卓 Chrome 部分版本无
|
||||
「继续」按钮的已知限制——验收时如实记录;桌面 Chrome/Firefox 为保底组合。
|
||||
|
||||
### 3.4 备选路线(不采用,写明理由)
|
||||
|
||||
- LiveKit 原生 TLS(7880 直接上证书):破坏通用 worker/8090(E4),**禁止**。
|
||||
- 系统 nginx 反代:.12 无运行中 nginx(E1/E2),安装/改系统配置超出零安装边界。
|
||||
- 忽略证书/不安全浏览器开关:明令禁止,不作为验收。
|
||||
|
||||
## 4. D1 音色(实际清单 + 零合成试听方案;不替用户定)
|
||||
|
||||
- **已证**(voices.json 实读,E7):音色共 **11 个 ID**——`bailu、bajie、default、
|
||||
female_soft、haimianbaobao、jiaojiao、male_warm、nezha、rain、sunwukong、
|
||||
xiaoyun`;每支 = zero-shot 参考音频克隆,参考文件
|
||||
`/opt/voice-agent/cosyvoice/voice_samples/<id>.wav` 实存(即该音色来源说话人
|
||||
的真实录音)。v1「6 支女声」及各主观描述系笔误+猜测,已删;不猜名字定效果,
|
||||
不引用通用演示状态(当前 `rain`)或其他测试/旧角色资料作为本用户选择。
|
||||
- **已证**:8090 面板**没有既有音色试听播放**(只有列表/切换/克隆上传/删除),
|
||||
且切换/上传写**共享** `voices.json`/`voice_state.json`、影响通用演示——v1
|
||||
「试听入口=8090 面板」勘误删除,未经授权不用它给本用户做试听。
|
||||
- **试听已交付(2026-10-27,零合成、零 GPU、零下载)**:`HEL-879-D1-参考试听包.zip`
|
||||
随 HEL-879 评论附件交付——自包含离线 `index.html` + 11 段参考 wav + `manifest.json`
|
||||
(逐文件 sha256 与服务器一致;来源与边界见 `docs/rework/hel879/d1-audition/`)。
|
||||
白栖知解压后用浏览器直接打开试听初选;音色效果以参考音频为初感 + 获批测试窗口内
|
||||
真实合成复核(计入 §6 TTS 计数)。参考录音原文按来源原样保留,不预筛。
|
||||
- 可选:克隆(录 5–20s 中文参考)需写共享 `voices.json`(新增条目为增量,但会触
|
||||
共享 TTS 热加载)→ **需单独授权**,默认不启。
|
||||
- worker 缺省回落 `default`(代码已证);专属 worker 用独立
|
||||
`voice_state_cybergril.json`,不写通用演示状态(runbook §4.1)。
|
||||
|
||||
## 5. 部署顺序(获批后执行;含回滚)
|
||||
|
||||
1. 统一实例(8360 + 8361 同进程双入口 + **8363 WSS 桥**,隔离数据目录与
|
||||
`/opt/voice-agent-cybergril/`、`/opt/cybergril-voice-certs/`;不动
|
||||
8300/8310/8320/8340/8350/8090/8081/7880/10095)。
|
||||
2. TTS 9880 重启:先核实 9880 无监听再按 cosyvoice 运维节启动;历史 `fuser -k`
|
||||
禁止照抄(当前已证停机,无需杀任何进程)。
|
||||
3. 专属 worker(`/opt/voice-agent-cybergril/`,agent venv 启动,健康口 8082,
|
||||
`CYBERGRIL_API_BASE=http://127.0.0.1:8360`)。
|
||||
4. `config/voice.yaml`(从 `config/voice.example.yaml` 复制):键
|
||||
`livekit_url: wss://192.168.200.12:8363`、`livekit_internal:
|
||||
http://127.0.0.1:7880`、api_key/api_secret 按 .12 现值只写服务器本地文件。
|
||||
- 回滚:停 worker → 停 8363 桥 → 停 8360/8361 → TTS 回停机或原状(全独立进程);
|
||||
Git 回退=本分支回退到 fc905fe 重新部署;冻结账与既有实例零接触。
|
||||
|
||||
## 6. 有限预算与停止条件(逐类;「代码硬闸」与「操作停机」分开写明)
|
||||
|
||||
**计数语义(已证,E10)**:budget 账 `acquire()` 在 provider 调用**发送前**原子
|
||||
预占——失败/重试/打断/后台调用同样计数;**LLM 调用数 ≠ 成功聊天行数**。ASR 流、
|
||||
TTS 分段、φ 播报、打断重合成、主动 say、闲置通话都**不等于** LLM 轮数,另列。
|
||||
|
||||
| 类别 | 建议上限(供拍板,不自动生效) | 计数位置 | 闸性质 | 异常停法 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| LLM 真实调用(dialogue 类,含语音轮与失败重试) | ≤40 次请求 / ≤500k tokens | 实例 budget 账 `request_usage`/`token_usage` 逐笔 | **代码硬闸已实现**:类别日顶+一次性总量+日 token 池发送前拒绝;封账库拒绝一切 | 到线自动停;异常扣费风险=立即停窗口(下 1–3 项全停) |
|
||||
| 嵌入 | **0**(R5 专项 stub) | semantic 账(`embed_ops` 未启用) | **代码硬闸已实现**(semantic cap=0 fail-closed);1b 另批 | — |
|
||||
| ASR(FunASR 流) | 测试窗口 ≤2h 且通话 ≤3 次 | worker 日志 job/stream 数(本地 CPU 服务,零外部计费) | **无代码闸(如实)**→操作停机 | 窗口到点/会话数到线/异常即停 worker |
|
||||
| TTS(CosyVoice 合成段,含 φ/打断重合成/主动 say/分段) | 窗口内 ≤200 合成段 | `tts.log` 合成行(本地 GPU,零外部计费) | **无代码闸(如实)**→操作停机 | 同上;GPU 显存异常(>8GB 或 OOM)即停 |
|
||||
| 语音会话(建房) | ≤3 次完整通话 | `POST /api/voice/session` 服务端日志 | **无代码闸(如实;列工程后续小项:建房数纳入 config 上限)** | 第 3 次结束或验收完成即停 |
|
||||
| 主动开口 | 默认关(`CYBERGRIL_PROACTIVE_VOICE` 不设) | — | 已实现默认关;如开只念已落库行、不新增 LLM 调用(已证代码路径) | — |
|
||||
|
||||
- **上限不自动生效**:所有 cap 配置当前仍 0,批准后由总管写入实例配置;权威账/
|
||||
冻结账不写、封账库永不重开;真实 cap 本轮=0。
|
||||
- 逐笔输出:budget 表逐行 + worker/tts 日志,窗口结束导出逐笔清单交主卡。
|
||||
- 本表数字为建议值,最终由白栖知定;**不以 30 轮聊天行数顶替任何账**。
|
||||
|
||||
## 7. 验收清单(R5 真机,integration-plan 原四条 + 补充)
|
||||
|
||||
1. 连续交谈 ≥3 轮(同一她、同档案、记忆延续,音色一致;R5 专项内「记忆」=
|
||||
档案与对话历史,语义记忆属 1b 不冒充)。
|
||||
2. 开口打断约 1 秒停声(VAD→TTS 截断;字幕同步消失)。
|
||||
3. 挂断立即停麦(track.stop + 房间删除;麦克风指示灯灭)。
|
||||
4. 无旧残音/残影(打断与掉线后旧帧不回显;已有普通离线用例通过,长会话防护等
|
||||
HEL-898 三项返修仍待交回统一复核,随后真机复验)。
|
||||
5. 网络失败/重开:诚实提示、重开仍是同一位她。
|
||||
6. **WSS 桥 8363 + 页面 8361 分端口信任**(§3.3),真机记录各浏览器行为;
|
||||
桌面 Chrome/Firefox 保底,移动端如实记录不硬闯。
|
||||
7. 字幕全生命周期(后台实际 v2 帧及前端状态单测已有证据;HEL-898 短回复显示、
|
||||
agent 离场与长会话防护返修尚未交回,不称界面层离线全通过;之后真机抽查
|
||||
增量→final→落库一致)。
|
||||
8. API 重启释放(房间与 worker job 真实回收)一次受控验证。
|
||||
9. 口型**不在本包**(不伪装接通)。
|
||||
|
||||
## 8. 真正待白栖知拍板的项(工程项已移出,见 §10)
|
||||
|
||||
1. D1 音色:听 `HEL-879-D1-参考试听包.zip` 后选 1 支(或另行授权克隆)。
|
||||
2. 有限真实用量与新增费用上限确认/调整(§6 各值;R5 专项嵌入 0)。
|
||||
3. 测试窗口与共享 TTS 重启授权(占 GPU ~5.6GB;ComfyUI 保持暂停到测试后与否)。
|
||||
4. 1b 完整统一体验的当前 37 项待准备依赖下载授权(目标 cp311 解析后核定实际
|
||||
产物清单,可与 R5 专项分开批;已有成品/缓存不重复下载;hatchling 已解决
|
||||
不再申请)。
|
||||
|
||||
> 集中请求口径(总管在主卡一次发出):试听包 + §6 逐类上限/费用 + §5 部署与
|
||||
> 回滚 + §1b 下载授权,四项一次说清,批准后按 §5 顺序执行;R5 语音专项
|
||||
> (stub、嵌入 0)与完整统一体验分开批、分开验,ASR/TTS/建房只有操作停机
|
||||
> 无代码硬闸,均如实表述。
|
||||
|
||||
## 9. 本包不做
|
||||
|
||||
不合并 PR#11/任何 PR;不替换 8300/8310 正式入口;不改队员运行时/模型/认证;
|
||||
不动冻结账与既有五实例;CG-011 完整会话中主动表达仍承接(默认关的「开场念一条
|
||||
旧留言」不冒充完整项);R6/R7 继续承接。
|
||||
|
||||
## 10. 工程已定项(工程核冲突后定案,不交用户选)
|
||||
|
||||
| 项 | 取值 | 冲突核对(2026-10-27 实测) |
|
||||
| --- | --- | --- |
|
||||
| 统一实例端口 | HTTP 8360 + HTTPS 8361 | 空闲(E1);与 8300–8350/8090/8081 不冲突 |
|
||||
| WSS 桥端口 | 8363 | 空闲(E1;本轮新增,v1 未列) |
|
||||
| worker 健康端口 | 8082 | 空闲(E1;8081 为通用 worker,差一位不误用) |
|
||||
| worker 目录 | `/opt/voice-agent-cybergril/` | 不存在、新建无冲突(E9) |
|
||||
| 证书目录 | `/opt/cybergril-voice-certs/` | 不存在、新建无冲突(E9) |
|
||||
|
||||
## 附 · 材料与证据指针
|
||||
|
||||
- .12 只读实测底稿:`docs/rework/hel879/unified-review/r5-facts-20261027.md`(脱敏)
|
||||
- WSS 桥:`deploy/voice/wss_bridge.example.py` + `wss-bridge-smoke.log`
|
||||
- 依赖分类:`docs/rework/hel879/release-artifacts.json`、`sdk-audit/sdk-audit.json`
|
||||
- 预算闸:`src/cybergril/think/budget.py`(acquire 语义)、`docs/budget-package-hel895.md`
|
||||
- 部署草案:`docs/runbook-hel877-voice.md` §4、`deploy/hel895-release-candidate.md` §2/§4
|
||||
@@ -0,0 +1,42 @@
|
||||
# HEL-879 统一整合审核 · 焦点2:seq 命名空间与 job/房间/控制器代次(2026-10-27)
|
||||
|
||||
问题(原作者 HEL-898 提出):`SubtitleBus` 的 `seq` 按 worker job 从 1 计(`src/cybergril/voice/worker.py` `entrypoint` 内建 bus),而前端 `VoiceController` 按**控制器会话**(一个 `Live`,web/src/voice/session.ts `live.seq`)记高水位。若同一房间在控制器会话存活期间换了新 job(worker 重连/新派发),新 job 的 seq 归零,前端要么误丢新帧、要么误收旧帧。本文件用 .12 真实 SDK 源码(livekit-agents 1.8.8 / livekit-api 1.2.1,`/opt/voice-agent/agent/venv/lib/python3.12/site-packages/`,SSH 只读取证,零写入零网络)与仓库代码逐条核清。
|
||||
|
||||
## 1. 一个 job 只跑一次 entrypoint(seq 计数器只生一次)
|
||||
|
||||
真实源码 `livekit/agents/ipc/job_proc_lazy_main.py`(默认进程执行器路径):
|
||||
|
||||
- L241–246:进程内已有运行中 job 时再收到 `StartJobRequest` 只告警跳过(`"trying to start a new job while one is already running"` → `continue`)——**一个 job 进程最多承载一个 job**。
|
||||
- L318–323:`_start_job` 为该 job 建 `JobContext` 并启动**唯一** `job_task`。
|
||||
- `_run_job_task`(L327 起)里 `self._job_entrypoint_fnc(job_ctx)` 只被创建为一个 task(`job_user_entrypoint`);job 在以下任一时刻结束:entrypoint 返回、`_shutdown_fut` 置位(room disconnected / shutdown 请求 / job 崩溃),随后 `_shutdown_job` → `_on_cleanup`,进程随 `_exit_proc_flag` 退出。
|
||||
|
||||
结论:worker.py 的 `entrypoint`(含 `SubtitleBus` 实例)在**一个 job 内恰好执行一次**,job 结束即进程结束,不存在「同 job 二次 entrypoint 导致 seq 归零」。
|
||||
|
||||
## 2. 断线重连不重跑 entrypoint(seq 不归零)
|
||||
|
||||
真实源码 `livekit/rtc/room.py`:
|
||||
|
||||
- L85–86 / L1130–1133:瞬断走 `reconnecting` / `reconnected` 房间事件——这是 `rtc.Room` 内部的信号/媒体重连,job 任务不重建,entrypoint 不重跑。
|
||||
- 只有房间真正关闭才发 `disconnected`;job_proc_lazy_main L288–293 将其置入 `_shutdown_fut`(reason=`room disconnected`)→ job 结束。此时房间已不存在,前端收到 `dropped`(livekit.ts L75),整个 `Live` 连同 `live.seq` 一起终结。
|
||||
|
||||
结论:**同一 job 内的 worker 重连,`SubtitleBus` 实例保留,seq 连续递增**;房间没了 = job 没了 = 前端这次通话也没了,不存在跨 job 的旧高水位。
|
||||
|
||||
## 3. 本产品没有「同房间第二个 job」的路径
|
||||
|
||||
- 后端唯一派发点:`src/cybergril/voice/session.py:396` `open_session` 内 `livekit_wire.create_dispatch(...)`,房间名 `cg-voice-` + 10 位随机(L394),每次 POST /api/voice/session 都是**新房间新派发**;`create_dispatch` 在 src/ 下仅此一处(grep 证据在库)。没有任何对既有房间补发/重发 job 的代码路径。
|
||||
- 前端 join 的就是该房间(grant.room),一个控制器会话 ↔ 一个房间 ↔ 一个显式派发 ↔ 一个 job ↔ 一个 `SubtitleBus`,五者一一对应。
|
||||
- 服务器侧 job 重投(resend)只发生在 job 从未启动时(无可供 worker 接单/启动超时):那时第一个 entrypoint 从未运行、从未发过任何帧,前端 `live.seq` 仍为 0,重投 job 从 1 计与前端水位天然一致。SDK 源码中不存在「已运行的 job 迁移到另一进程」的机制(job 进程即 job 本体,崩溃即终止;livekit-agents 侧无 resend 代码,grep `resend` 仅命中无关模块)。
|
||||
|
||||
## 4. 真实残余缺口(非 seq,但同场景):worker job 中途死亡 = 前端僵尸「listening」
|
||||
|
||||
job 死亡(worker 进程崩溃/被运维重启)时:agent participant 离开房间,但**房间仍在**(用户还在),前端收不到 `dropped`(它只挂 `Disconnected`,web/src/voice/livekit.ts L69–75 只处理 `ParticipantConnected`/`DataReceived`/`Disconnected`/`AudioPlaybackStatusChanged`),页面停在最后相位(多为 listening),再无任何帧。`RoomEvents` 无 agentLeft。这不破坏 seq 或旧帧防护(没有第二命名空间),但用户会面对一个没有她的「通话中」。有限修复建议(归原作者,前端):`livekit.ts` 增加 `ParticipantDisconnected`(agent 身份)→ `RoomEvents.agentLeft` → `VoiceController` 以诚实话术收场(与 dropped 同路径、不删她的话轮)。后端无需改动。
|
||||
|
||||
## 5. 可执行复核方式
|
||||
|
||||
- 证据 A(本轮):`scripts/gen_hel879_unified_frames.py` 在 .12 真 SDK 上驱动实际 worker 回调生成全部 v2 帧(见 frames/),各场景 seq 严格递增、每 speech 恰一次 `turn_start`。
|
||||
- 证据 B(源码引用,可重复):本文第 1/2/3 节的 file:line 均可在 .12 venv 直接核对;`.12` 只读 SSH stdin。
|
||||
- 证据 C(前端侧):`web/tests/hel879_frames.test.ts` 用实际 worker 帧验证 replay/迟到/乱序帧全部被 seq+speech 双门拦下;「新通话 = 新房间 = 新序列」在 drop+重开用例中验证(旧房间帧不再影响新 `Live`)。
|
||||
|
||||
## 6. 结论
|
||||
|
||||
**现网代码内,seq 命名空间 = job = 房间 = 控制器会话,一一对应;不存在「同房间新 job 序号归零」的产品路径或 SDK 机制。** 前端以控制器会话记高水位是安全的,且对任何假设的第二命名空间表现为 fail-closed(旧水位丢弃全部低 seq 新帧,不会把旧帧当新帧收)。唯一真实缺口是 §4 的 agent 离场僵尸界面(🟡 建议项,归原作者)。
|
||||
@@ -0,0 +1,44 @@
|
||||
# HEL-879 统一整合审核记录(2026-10-27)
|
||||
|
||||
整合对象:`hel-879-assembly` @ fc905fe(后台时机收口)+ `origin/hel-898-preserved` @ fb7ea84(总管逐字节保全的 HEL-898 前端接线,作者代码 46ac0a7)。本审核不开新串、不重审已过内核(预算/备份/恢复/绑定/三处时机/总管 898 六项检查均沿用其通过记录)。
|
||||
|
||||
## 统一 head
|
||||
|
||||
`hel-879-assembly` 快进至 **fb7ea84 + 本轮审核提交**(审核物:帧生成脚本、fixtures、前端用例、浏览器回放 harness、SDK 取证、R5 测试包、handoff 追加)。与 fc905fe 的差异 = HEL-898 的 8 文件(6 web/tests+docs/handoff-898+2 web/src:ChatPanel.tsx/session.ts,总管已核逐字节=作者附件)+ 本轮审核新增文件;`web/src` 除作者两文件外零改动,`src/` 零改动,PR#11 与 hel-870-assembly 未动。
|
||||
|
||||
## 焦点1 · 实际 worker 帧 → 当前前端(功能)
|
||||
|
||||
**帧来源**:`scripts/gen_hel879_unified_frames.py` 在 .12 真实 SDK(livekit-agents 1.8.8 / livekit-api 1.2.1,SSH 只读 stdin,零写入零网络)驱动**实际 worker 接线**(`make_voice_llm` 归属绑定 + `bind_voice_session` 真回调 + 真 SpeechHandle 生命周期 + `speak_proactive_row`)生成五套 v2 帧(frames/ + web/tests/fixtures/hel879/)。唯一替身=HTTP 客户端(离线注入 /api/chat SSE)与播放时钟(`_mark_done`/`interrupt` 定时器)。
|
||||
|
||||
场景与结果(vitest `web/tests/hel879_frames.test.ts` 9/9,实际帧逐帧喂 `VoiceController`):
|
||||
|
||||
| 场景 | 帧序列(实测) | 前端行为(断言) |
|
||||
| --- | --- | --- |
|
||||
| normal | interim→user_final→turn_start→3×interim→**final→end**(receipt ack ✓) | 增量替换生长;final=存稿原文;落库回读接替:`voice-<speech>` 键→存档行 id(同 turn),mergeTurns 恰加一次 |
|
||||
| interrupt | cut 轮 **无 final 只有 cancel(interrupted)**;下一轮干净 final+ack | 被切行立即清;迟到帧(新 seq、死 speech)不回显;下一轮独立落库一次 |
|
||||
| φ | interim(φ)→error(φ 原句)→cancel(error_phi),无 ack | spoken 槽可闻不入档;her 即清 |
|
||||
| no_receipt | **cancel(no-receipt),无 final**(fc905fe 门实测生效) | 无任何「她的回复」残留 |
|
||||
| proactive | start **播放中**(sidecar `start_while_playing=true`)→end;打断变体→cancel(interrupted) | 她的位置整句显示、绑定存档行 id;打断即清;页面零写请求 |
|
||||
|
||||
打断/文字接管/掉线重开(vitest 全过):user_final 立即关她当前 speech;interim 不抢清(由服务端 cancel 定夺);`hush()` 文字接管即清行+静音;`dropped` 整通话收场清残影;重开=新房新序列,旧房间帧无效。舞台身份与键接替(voiceLine/mergeTurns)用实际帧 turn_id 验证。
|
||||
|
||||
**界面层**:本机缺浏览器 GUI 系统库(libatk/libgbm 等十项,chromium/chrome-headless-shell 均无法启动),零安装授权下**未独立复跑浏览器**。`web/tests/hel879_unified_shots.mjs`(自持 mock+CDP,回放实际 worker 帧、双主题双尺寸)已入库,供有 Edge/Chromium 环境一键回放。界面证据仍=作者 61/61 假 LiveKit 浏览器与两主题截图(总管保全,未复跑,不称独立通过)。**录屏:本轮无新连续帧/视频产出,如实列未交。**
|
||||
|
||||
## 焦点2 · seq 命名空间与 job/房间/控制器代次
|
||||
|
||||
结论(详见 `seq-job-analysis.md`,全部 file:line 指向 .12 真 SDK 源码):**job=房间=派发=控制器会话一一对应,无「同房间新 job 序号归零」路径**。一 job 恰一次 entrypoint(job_proc_lazy_main L241-246/L318-323);RTC 瞬断走 reconnecting/reconnected 不重跑(rtc/room.py L85-86/L1130-1133),房间真断=job 结束=前端 Live 同终;后端唯一派发点 session.py:396 每次新房(10 位随机名);服务器重投仅限从未启动的 job(从未发帧,水位天然一致)。若假设性第二命名空间出现,前端表现为 fail-closed(丢帧而非收旧帧)。**残余缺口(🟡 归原作者前端)**:worker job 中途死亡(进程崩溃/重启)时 agent participant 离场但房间仍在,livekit.ts 无 agentLeft → 页面僵尸「listening」。有限修复:`ParticipantDisconnected`(agent 身份)→ 诚实话术收场;后端无需改。
|
||||
|
||||
## 焦点3 · closed 64 上限与长会话/清理边界
|
||||
|
||||
- **DOCUMENTED GAP(🟡 归原作者,非现网可触发)**:64+ 后续关闭把退休 speech 挤出窗口后,**重复高 seq turn_start 可重进**(vitest 用例以对抗帧实证:重进→重放终稿可再次立为她的行)。现 worker 无法产生该帧(SDK speech_id 每话唯一、`interim.begin` 每流一次、无重发路径),触发需第二/失常来源——与焦点2结论一致。防御性修复建议:`closed` 改无界 `Set<string>`(每通话 speech 数有 TTL 上界,内存可忽略)或对 turn_start 增加按 job 内序号窗的约束。
|
||||
- 新用户 interim→cancel/终稿清理边界(vitest 全过):interim 只更新 heard 不清她的行(打断由服务端定夺);user_final 立即关闭当前 speech 并清行;cancel/final/turn_end 的即时清理由实际帧验证。
|
||||
- 舞台回读/身份与键接替:实际帧 turn_id 驱动(焦点1 表),非单测数字。
|
||||
|
||||
## 回归与需求检查
|
||||
|
||||
- pytest **352/352**(py3.11 venv);vitest **108/108**(作者 99+本轮 9);typecheck/build 通过;lint 0 错 1 既有 fullButton 警告;ruff(src/tests/tools) 0 错。
|
||||
- 需求检查 4/4:origin/main 与 fc905fe 各带/不带更新后的 handoff-HEL-879.json(本目录 requirements-*.log)。v1.11/60 项无需求变更;总管 898 四项检查沿用。
|
||||
|
||||
## 边界
|
||||
|
||||
零真实 LLM/嵌入/ASR/TTS/麦克风、零下载/安装/部署/合并;.12 仅 SSH 只读取证(含一次 nvidia-smi/端口探活供 R5 包);真实 cap=0;不选音色、不改绑定、不碰旧服务/档案/冻结账。R5 真机包材料(`r5-test-package.md`)仅备齐待批,未执行。完整 CG-011、R6/R7 继续承接。
|
||||
@@ -0,0 +1,21 @@
|
||||
# wss_bridge.example.py 本地冒烟(2026-10-27,零外网、回环 only)
|
||||
|
||||
- 一次性本地自签证书(CN=local-bridge-test,2 天有效期,仅本测试)。
|
||||
- dummy 上游 127.0.0.1:18880(读 5 字节回 echo);桥 127.0.0.1:18363 → 18880。
|
||||
- 结果:TLSv1.3 握手成功;`sendall(b"hello")` 经桥穿透后收到 `b"echo:hello"`。
|
||||
- 结论:TLS 终结 + 字节透明转发路径可用;.12 实部署与 LiveKit 真实信令仍属
|
||||
拟议/待真机(本冒烟不证明后者)。
|
||||
|
||||
```
|
||||
$ python3 deploy/voice/wss_bridge.example.py --listen 127.0.0.1:18363 \
|
||||
--upstream 127.0.0.1:18880 --cert cert.pem --key key.pem &
|
||||
wss-bridge(PROPOSAL) tls ('127.0.0.1', 18363) -> ('127.0.0.1', 18880)
|
||||
|
||||
$ python3 - <<'PY'
|
||||
ctx = ssl.create_default_context(); ctx.check_hostname=False; ctx.verify_mode=ssl.CERT_NONE
|
||||
s = ctx.wrap_socket(socket.create_connection(("127.0.0.1", 18363), timeout=5))
|
||||
print("TLS:", s.version()); s.sendall(b"hello"); print("payload:", s.recv(64))
|
||||
PY
|
||||
TLS: TLSv1.3
|
||||
payload: b'echo:hello'
|
||||
```
|
||||
@@ -0,0 +1,87 @@
|
||||
# HEL-879 · 语音接缝接口与验收(交原视觉作者接线;总工不改已认可 web/src 视觉)
|
||||
|
||||
> 背景:总管独立复核指出「CG-011 语音主动开口 no-op、她的增量字幕缺失」是
|
||||
> **实现缺口**,不能归为「等音色/预算就能自动完成」。本文件给出后台已落地的
|
||||
> 最小接缝、前端需要补的**精确接口**与**验收标准**。代码基点:分支
|
||||
> `hel-879-assembly`(见交付评论精确 head);后台实现
|
||||
> `src/cybergril/voice/seam.py` + `worker.py` 接线。
|
||||
>
|
||||
> **2026-10-27 收口更新**:字幕消息已升级为**版本化契约 v2**(信封
|
||||
> `v/seq`、确切轮次 `speech_id`、显式起止/取消事件、迟到/乱序保护、主动
|
||||
> 播报同源 `message_id`)。完整可执行契约与录制样例见
|
||||
> `docs/voice-subtitle-contract-v2.md` 与
|
||||
> `docs/rework/hel879/subtitle-samples/*.jsonl`——**接线卡(HEL-898)以
|
||||
> 该契约为准**,本文 A 节的 v1 语义作为兼容背景保留。
|
||||
|
||||
## A. 她的增量回复字幕(assistant_interim)
|
||||
|
||||
### 现状与缺口
|
||||
- 用户侧 ASR 字幕已齐:`interim`(ASR 草稿)与 `user_final`(纠错终稿)在
|
||||
`web/src/voice/session.ts` 已渲染(现有 `interim` 分支当「听到用户在说」处理,
|
||||
**不能复用来渲染她的回复**——那是另一个语义)。
|
||||
- 缺的是**她**的回复在 TTS 首包前/播放中的增量文字。后台现已补齐:worker 把
|
||||
/api/chat SSE 的每个 delta 累积后发布到同一 `cg.subtitle` 通道。
|
||||
|
||||
### 后台已交付(无需前端改动即生效的数据)
|
||||
- 数据通道:topic `cg.subtitle`(不变)。
|
||||
- 新 kind:`assistant_interim`,`role: "assistant"`,`text` 为**截至当前的完整
|
||||
回复文本**(替换语义,同用户 interim;发布时机=SSE 分片到达,先于/伴随 TTS)。
|
||||
- 既有 kind 不变:`assistant_final`(已落库的完整回复,播放完成且未打断后发)、
|
||||
`error`(φ 原句,未落库)、`interim`/`user_final`(用户侧)。
|
||||
- fail-closed 语义不变:打断/失败/无回执的轮**只有 interim,不会有 final**——
|
||||
前端必须把无 final 收尾的 interim 按「这轮没有成为她的正式回复」处理。
|
||||
|
||||
### 前端需补(原视觉作者;具体视觉由其定)
|
||||
1. `web/src/voice/session.ts` 字幕分支:新增 `assistant_interim` 处理(当前
|
||||
`if (s.kind === 'interim')` 只覆盖用户草稿)。
|
||||
2. 渲染位置/样式:与 `assistant_final` 同一气泡位(建议替换式过渡),与用户
|
||||
`heard` 视觉可区分;**不进入正式聊天记录**(只有 final 落库)。
|
||||
3. 收尾规则:`assistant_final` 到达 → interim 消失、final 生效;`error` 到达 →
|
||||
interim 消失、按现有 error 呈现;被打断(无任何收尾)→ 下一次 interim 或
|
||||
新轮开始时清掉;挂断 → 清掉。
|
||||
|
||||
### 验收(离线可测,无需真实通话)
|
||||
- [ ] 用假 LiveKit/假音频脚本回放 `cg.subtitle` 序列
|
||||
`interim(user) → user_final → assistant_interim("她在") →
|
||||
assistant_interim("她在打字中") → assistant_final("她在打字中。")`,
|
||||
页面按序呈现且 interim 被 final 原子替换。
|
||||
- [ ] 打断负例:`assistant_interim` 后直接新的 `interim(user)`(无 final/error),
|
||||
她的 interim 残影不越过新用户轮。
|
||||
- [ ] φ 负例:`assistant_interim` → `error`,error 文案呈现且不落正式记录。
|
||||
- [ ] 全程零新增权限申请、零非回环出站(沿用 HEL-896 浏览器检查口径)。
|
||||
|
||||
## B. CG-011 语音主动开口(最小接缝,默认关闭)
|
||||
|
||||
### 后台已交付
|
||||
- `worker.py _maybe_open_proactive`(真实代码路径,`CYBERGRIL_PROACTIVE_VOICE=1`
|
||||
才启用;**默认关**,等接线卡与呈现批准):
|
||||
- 数据来源:与文字收件箱同一 `GET /api/messages`(`ChatApiClient.recent_messages`),
|
||||
只选**服务端已落库**(`proactive=1`、`role=companion`、`status=sent`、非空、
|
||||
本房间未念过)的行,最新优先,每会话 ≤1 条(`PROACTIVE_PER_SESSION`)。
|
||||
- 播报:`session.say(text, allow_interruptions=True)`——可被用户打断;
|
||||
无新模型调用、无第二人格、**无第二条回执通道**(文字回执规则独立且已存在)。
|
||||
- 失败 fail-closed:接缝任何异常只记日志跳过,不影响会话开启。
|
||||
- 选择逻辑独立在 `seam.py pick_proactive/pending_proactive`(离线可测,
|
||||
`tests/test_voice_rework_hel879.py` 三例覆盖)。
|
||||
|
||||
### 前端/接线卡需定(原视觉作者 + 总管,经用户批准后启用)
|
||||
1. 入口呈现:她主动开口时页面如何呈现(字幕走 `assistant_final` 同位?
|
||||
是否复用留言卡「回她」入口语义?未读标记如何联动——**worker 不代标已读**,
|
||||
阅读态仍归页面)。
|
||||
2. 节奏:会话开启后何时念(现在=开启即查一次、每会话最多一条);是否需要在
|
||||
会话中轮询新 proactive(后续卡,不默记完成)。
|
||||
3. 打断呈现:用户开口打断她的主动播报时,字幕按打断负例处理(无 final 收尾)。
|
||||
|
||||
### 验收(启用后)
|
||||
- [ ] 预置一条落库 proactive 行 → 开语音会话 → 她原文念出该行(与文字收件箱
|
||||
同一行、一字不差),字幕按定稿呈现。
|
||||
- [ ] 播报中用户开口 → 立即被打断、无残音;该行不被标记已读(除非用户在页面
|
||||
读它)、无回执伪造。
|
||||
- [ ] 无 proactive 行 → 会话正常开启,静默。
|
||||
- [ ] API 不可达 → 接缝跳过,语音会话不受影响。
|
||||
|
||||
## 边界
|
||||
- 本文件只交接口与验收;**总工未改任何已认可 web/src 视觉**(本卡 web/src 仅
|
||||
勘正 session.ts 一处无证据注释,无逻辑/样式改动,diff 见交付评论)。
|
||||
- R5 真机验收(≥3 轮、1 秒打断、停麦无残音、可信 HTTPS/WSS、D1 音色、有限
|
||||
预算)仍待主卡集中批准,接缝通过≠R5 完成。
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"head": "e29105875440b88c7951c399ee29c4931bf55a60",
|
||||
"real_llm_requests": 0,
|
||||
"real_embeddings": 0,
|
||||
"embedding_boundary": "deterministic 512-dim; no model loaded",
|
||||
"external_network": "socket.connect rejects non-loopback",
|
||||
"stub_batch": {
|
||||
"backend": "stub",
|
||||
"state": "done"
|
||||
},
|
||||
"mem0_enqueue_count": 1,
|
||||
"mem0_batch_after_tick": {
|
||||
"state": "done",
|
||||
"reason": null,
|
||||
"entry_ids": "[\"38bfb1e0-9f9b-4b1f-85c3-8b437d140e53\"]"
|
||||
},
|
||||
"mem0_hits": [
|
||||
{
|
||||
"id": "38bfb1e0-9f9b-4b1f-85c3-8b437d140e53",
|
||||
"memory": "合成提取记忆HEL874-1"
|
||||
}
|
||||
],
|
||||
"mem0_reenqueue_after_done": 0,
|
||||
"embed_ledger_used": 4,
|
||||
"llm_ledger_used": 1,
|
||||
"deterministic_vector_items": 3
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
# HEL-882 · 硬闸/恢复/发布包修正证据
|
||||
|
||||
读取提交:本目录 JSON 的 `head` 字段(`e29105875440b88c7951c399ee29c4931bf55a60`,
|
||||
最终交付 head 见交付评论——本目录随证据一次追加提交)。全部运行零真实 LLM、
|
||||
零真实嵌入(确定性 512 维替身)、零非回环出站、权威三账零写入。
|
||||
|
||||
## 1. 总管两复现脚本原样复跑(仅改仓库路径与 head)
|
||||
|
||||
脚本:`review_hel882_sdk.py` / `review_hel882_api.py`(与总管附件逐行同构,
|
||||
HEL-874 原版在总管附件)。结果对比:
|
||||
|
||||
| 复现 | e978e87(总管复现) | 本 head(复跑) |
|
||||
| --- | --- | --- |
|
||||
| api:日 token 超限仍发请求 | 1 次 provider 请求、chat.final、已用 2962→5005 | **0 次请求、chat.error、已用 2962 不变**(manager-review-api-rerun.json) |
|
||||
| sdk①:llm_cap=1 撞 500 隐藏重试 | 6 次 HTTP、llm_ops=0、max_retries=2 | **1 次 HTTP、llm_ops=1、max_retries=0**,第二次 add 发送前拒绝(manager-review-sdk-rerun.json) |
|
||||
| sdk②:embed 中途耗尽被吞 | done/[],调 cap 后仍 done、enqueue=0 | **首 tick queued(reason=semantic_add_swallowed_failure:…budget_exhausted,attempts 不耗);调 cap 后同批续跑 done 且 entry_ids 非空** |
|
||||
| sdk③:stub→mem0 同档案 | enqueue=0、真实库无命中 | **enqueue=1**(脚本本身不 tick;补证见 §2) |
|
||||
|
||||
## 2. 补证:stub→mem0 重整全链(真实固定 SDK + 确定性替身)
|
||||
|
||||
`addon_stub_switch_hel882.py` → `HEL-882-sdk-addon-stub-switch.json`:stub 批
|
||||
done 后切 mem0,enqueue=1 → tick → **done + 真实 entry** → search **命中** →
|
||||
再次 enqueue=0(真实完成批不重发)。同边界:零模型加载、禁非回环。
|
||||
|
||||
## 3. 固定安装合同验证(工具本体,确定性边界)
|
||||
|
||||
`real-sdk-hel882.json`:`tools/verify_mem0_real_hel874.py` 12/12 通过;
|
||||
`embedding_boundary` = TextEmbedding 构造前确定性 512 维替身、零模型加载;
|
||||
`final_embed_rows`/`final_llm_used` 在清理临时目录前落盘(逐笔可审计)。
|
||||
e978e87 版真实嵌入勘正见 `../hel874/erratum-hel882.json`。
|
||||
|
||||
## 4. 发布包离线核验
|
||||
|
||||
`release-offline-hel882.json`:`tools/check_release_offline_hel882.py` 全过——
|
||||
R1 空目录 checkout、R2 lock-only venv + PYTHONPATH 服务 import/health
|
||||
(R4-assembly / stub)、R3 未批上限 fail-closed(创建可过、对话在 provider 前
|
||||
拒绝并如实 chat.error)、R4 填批准值后全链(echo 替身、409=数据已在)、
|
||||
R5 停止后数据保留、重开 epoch+1、R6 mem0 同进程导入缺项(3.11 无 wheel,
|
||||
解决路径 deploy/hel874-release.md §4,本卡零下载)。
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user