摘要:Codex 和 Claude 并没有为这块小屏幕提供统一状态 API。VibeStick Bridge 如何从本地进程、JSONL 会话和限额事件中构造可靠状态?本文分析 provider 抽象、状态推断、HTTP 协议与安全设计。

先纠正标题:Bridge 没有窃听提示词,也不需要把聊天内容上传到某个神秘中转站。它做的是“观察”本机 Agent 留下的运行痕迹,然后把少量状态翻译成 StickS3 看得懂的 JSON。

这件事听起来像侦探工作,实际更像看办公室门口的灯:进程在不在、最近有没有活动、最后一条事件是什么、配额数据是否过期。看得到有人加班,不代表要趴门缝里听会议内容。

一、统一 provider 层:先把方言翻成普通话

bridge/src/vibe_stick/providers/base.py 定义了 ProviderObservation。Codex 和 Claude 的观察器最终都要交出同一份答卷:

@dataclass
class ProviderObservation:
    provider_id: str
    display_name: str
    online: bool
    status: AgentStatus
    project: str
    quota_5h_remaining: int | None
    quota_7d_remaining: int | None
    quota_updated_at: str
    quota_stale: bool
    alert_type: str
    alert_message: str
    alert_event_id: str
    latest_event_timestamp: datetime | None = None

Bridge 的 BridgeStateStore 同时刷新两个 provider,再根据 VIBE_STICK_PROVIDER=auto|codex|claude 选择活动对象。自动模式还保留上一次选择,避免两个 Agent 状态接近时屏幕左右横跳,像一个同时追两场球赛但遥控器接触不良的人。

下面是 Bridge 从两个 Provider 获取观察结果,经过状态推断和选择逻辑,最终生成统一状态输出的完整流程:

Claude Provider 观察器

Codex Provider 观察器

auto

codex

claude

扫描 ~/.codex/sessions 目录

读取 JSONL 文件尾部

解析进程状态与事件

推断状态: DONE/APPROVAL/ERROR/OFFLINE

提取配额数据

读取项目 JSONL 文件

解析事件与 permissionMode

判断 tool_use 是否需审批

推断状态: APPROVAL/其他

尝试获取 5H/7D 配额

生成 Codex ProviderObservation

生成 Claude ProviderObservation

BridgeStateStore 同时刷新

根据 VIBE_STICK_PROVIDER 选择

保留上次选择
避免状态接近时横跳

选择 Codex 观察结果

选择 Claude 观察结果

生成统一状态输出

/state API 响应
包含 provider、quota、alert 等

状态落盘存储
带时间戳标记 stale

所以屏幕展示的是本地会话中最近一次可见的限额快照,不是 OpenAI 官方 quota API。快照会落盘;新值暂时取不到时,旧值继续展示并标为 stale。工程上,带时间戳的旧数据通常比突然“失忆”(无数据)更有用,前提是老老实实告诉用户它旧了。

三、Claude:tool_use 不一定等于等待审批

Claude 观察器同样读取项目 JSONL,但状态推断更细。它记录最新普通事件、错误、完成事件、tool use,以及每个 session 的 permissionMode

关键判断是:只有 tool use 是最新事件、处于时间窗口内,并且该 session 为 default 权限模式时,才认为 APPROVAL。在 acceptEditsauto 或 bypass 模式下,工具调用会自动继续,不能见到 tool_use 三个字就替用户拉响审批警报。

Claude 5H/7D 用量是 opt-in。启用后 Bridge 会尝试使用本机 Claude Code 登录凭据访问非公开 endpoint,并设置最短轮询间隔。失败后保留旧快照并标 stale;从未成功时显示 --%。因为接口未公开,这项能力随上游变化而失效的风险必须写进产品说明,而不是藏进脚注的脚注。

四、状态存储:线程安全比“反正请求不多”可靠

Bridge 基于标准库 ThreadingHTTPServer。多个请求可能同时触发状态刷新、录音和配额更新,因此 BridgeStateStore 使用 threading.RLock 保护内存状态与落盘。

主要接口包括:

方法 路径 用途
GET /state 获取 provider、quota、alert 与 Bridge 元数据
GET /health 获取版本、Python 路径和 QR 支持状态
GET /setup 本机管理页,仅 loopback 可访问
POST /event 按键事件和手工状态
POST /quota/refresh 强制刷新活动 provider 配额
POST /recording/start 创建录音 session
POST /recording/audio 上传 PCM 二进制
POST /recording/stop 转写、粘贴或重试

Bridge 在 /state 响应中附加名称、版本等元数据,日志也记录固件名称、版本和 transport header。这为未来的协议兼容检查打了基础,虽然当前还没有完整的版本协商机制。

五、安全:Token 是门锁,不是防空洞

当 Bridge 绑定 0.0.0.0 等非 loopback 地址时,启动逻辑会拒绝空 Token 和常见占位值。设备通过 X-Vibe-Stick-Token 认证,服务端使用常量时间比较。UDP 发现请求也必须带相同 Token,否则 Bridge 保持沉默。

其他防线包括:

  • 管理页只允许 loopback 客户端;
  • 录音请求有默认 2 MB 大小限制;
  • /state、录音和事件接口都在受保护路径集合中;
  • 管理页响应禁用缓存;
  • HTTP API 不返回 ASR key、agent token 或原始 Claude usage 响应。

但局域网音频仍使用明文 HTTP,共享 Token 也还没有设备级轮换和撤销。当前方案是在受信任 LAN 上为原型提供基础保护,不等价于端到端加密。未来需要安全配对、单设备凭据、NVS encryption,必要时再评估 TLS 或应用层加密。

六、这个观察器架构的脆弱点

本地观察是一种聪明但现实的折中,也有三个天然风险。

第一,上游 JSONL schema 可能变化。解析必须对缺字段、坏行和新事件类型保持宽容,并用 fixture 测试固定已知样本。

第二,状态是推断而非真相。四分钟活动窗口只是经验值;长时间运行的工具可能让 Agent 实际在忙但日志暂时安静。

第三,轮询成本会随会话增多上升。当前通过限制文件数和 tail bytes 控制成本;更大规模时可引入文件游标、增量索引或事件订阅。

好架构不是假装这些问题不存在,而是把不确定性关进 adapter,让设备协议保持稳定。上游方言变了,改观察器;小屏幕不必跟着重刷人生观。

下一篇进入跨平台现场:VibeStick 如何从 macOS 走向 Windows,以及为什么“能启动”离“能交付”中间还隔着防火墙、安装器和一只托盘图标。


本文分析的是本地兼容与实验性观察机制,不代表 OpenAI 或 Anthropic 提供、认可上述状态与 quota API。

Logo

葡萄城是专业的软件开发技术和低代码平台提供商,聚焦软件开发技术,以“赋能开发者”为使命,致力于通过表格控件、低代码和BI等各类软件开发工具和服务,一站式满足开发者需求,帮助企业提升开发效率并创新开发模式。

更多推荐