跳到主内容
Spark

开源MIT · 四端同一协议 · 事件溯源

Web 工作台

流式对话、工具调用可视化、fail-closed 人工审批。27 种事件实时驱动四端界面,会话以 append-only JSONL 落盘,可回放、可分叉、可回滚。

MIT License · Node.js ≥ 24 · 默认监听 127.0.0.1:4318 · 数据落盘 ~/.spark

给 Agent 派个活

先读后改,改动走审批。 写类工具与 bash 需人工确认——once / always / reject 三种答复,超时未答复自动拒绝(fail-closed)。

permission.resolved { reply } · fail-closed

开发者

一份协议,驱动四端界面。

事件词表、zod schema、applyEvent reducer、Transport 全在 @spark/protocol——是运行时代码,不是类型包。断线按 seq 续播,回放重建完整界面。

27
事件词表
28
内置命令
4
端形态
import { createClient }  from "@spark/sdk";// HTTP 客户端:装配 HttpTransport + 便利分组(ADR D30)const client = createClient("http://127.0.0.1:4318");// 事件流是 UI 的唯一状态源:SSE 按 seq 续播client.events.subscribe((envelope) => {  // 27 种事件经 applyEvent 折叠成 UI 状态});

核心能力

四项能力共用一份事件词表:流式渲染、工具状态机、审批卡、四端同步 都是同一套 reducer 的不同分支。

01

流式对话

模型输出按 token 切成 assistant.delta 事件推送,四端各自用同一份 applyEvent reducer 把事件流折叠成 UI 状态。delta 类事件是 live-only:不落盘,断线重连后由 durable 的 assistant.message 重建终态。

assistant.delta · reasoning.delta · tool.progress = live-only

Web 端会话截图:左侧会话列表,右侧流式对话面板
02

工具调用可视化

工具状态机 started → progress → completed 全程上屏:输入、输出、耗时(durationMs)、是否错误(isError)都是事件字段。失败时错误码(E_PATH_OUTSIDE / E_SANDBOX_UNAVAILABLE 等)同屏呈现。

tool.started { input } → tool.completed { output, isError, durationMs }

桌面端截图:Electron 壳内的工具调用详情面板
03

人工审批

permission.asked 弹卡,答复只有 once / always / reject;超时、异常、中断一律结清为 reject(fail-closed)。审批事件是 log-only:永不进模型历史,但 durable 落盘,事后可回放每一次决策。

permission.resolved { reply: 'once' | 'always' | 'reject' }

移动端截图:审批弹窗与对话流
04

四端同一协议

Web、Desktop、CLI、Mobile(含小程序)共享 @spark/protocol 的 27 种事件词表与 Transport 接口。词表扩展走 declaration merging,schema registry 是唯一来源,四端不会各自漂移出一套事件名。

@spark/protocol · 27 种事件 · Web / Desktop / CLI / Mobile

CLI 端截图:Ink 7 终端 TUI 纯单栏会话流

架构一览

五层:四端 UI / 协议 / 服务端 / 引擎 / 会话文件。

apps/*四端 UI(Web · Desktop · CLI · Mobile)
@spark/protocol27 种事件词表 · zod schema · Transport
apps/serverFastify · SSE · 仅绑定 127.0.0.1
@spark/engineInputQueue → RunLoop → ToolPipeline
sessions/*.jsonldurable append-only · 完整可回放

↓ data flow: user input → engine → events → UI

安全模型

缺省绑定回环;审批超时、异常、中断一律结清为拒绝;路径越界先于 审批拦下;事件全程 append-only 落盘。

  1. 缺省绑定回环

    server 缺省只监听回环地址,会话数据全部落在本机 ~/.spark/ 下。需要对外暴露时(非环回绑定)强制开启配对鉴权:6 位短码换长效 token。

    server: { host: '127.0.0.1', port: 4318 }
  2. Fail-closed 审批

    写类工具与 bash 必须人类确认,答复只有 once / always / reject 三种。超时、异常、中断、级联、模式切换一律结清为 reject,审计主体记 system;bash 工具缺省全审批。

    timeout → permission.resolved { reply: 'reject' }
  3. 硬边界先行

    允许根 = cwd,路径 resolve 归一后越界直接抛 E_PATH_OUTSIDE,发生在审批之前而不是事后审计。可选的 bash 沙箱走平台 wrapper 前缀(Linux bwrap / macOS Seatbelt),wrapper 不可用即拒跑,不降级裸跑。

    resolveInRoot → E_PATH_OUTSIDE
  4. Durable 可审计

    append-only JSONL:第 0 行是 header,其后每行一个事件信封,seq 等于文件行号。只追加不改写,因此可回放、可分叉、可回滚(checkpoint)。

    ~/.spark/sessions/<mungeDir(cwd)>/<ts>_<id>.jsonl

两条起步路径

在终端里跑

npm 发布落地前先 clone 源码:装一次依赖、出一条 server bundle,一条命令进 TUI。

  • Node.js ≥ 24 · pnpm 9(源码跑)
  • node apps/cli/dist/main.js up → TUI,server 缺省 127.0.0.1:4318
  • 首回合前配一次模型:~/.spark/models.json
  • 退出连带回收 server,会话落盘 ~/.spark/sessions/

先读源码与文档

从协议包读起:事件词表与 Transport 是四端共享的运行时核。

  • 27 种事件 · applyEvent reducer 逐一单测
  • MockTransport 与 HttpTransport 同构,前端可脱离后端开发
  • 契约用例与词表页生成物入库,CI 校同步
  • MIT · 复用代码保留版权声明

MIT 许可 · 默认只监听 127.0.0.1 · 无账号体系