Command Palette

Search for a command to run...

tomori0nao/sym-service
Public
wasmer run tomori0nao/sym-service

sym-service — 多 runtime 符号计算网关

一个 worker 干两件事:出静态文档站,以及给两个不同 runtime / 架构的符号计算后端做统一入口。

                                  ┌─ SYMBOLICA_URL → Unikraft Cloud(Rust + Symbolica,x86_64)
客户端 →  WinterJS (WASIX)  ──────┤
          dist/worker.js          └─ SYMPY_URL ────→ Wasmer Edge(CPython + SymPy,wasm32-wasip1)
          ├─ 静态页(Astro 构建产物,内联成资源表)
          └─ POST /v1/evaluate · GET /v1/capabilities · GET /healthz · GET /

网关不发明协议。 两个上游早已是同一套形状(单端点 + op 闭集 + 五段信封 + result.values[] + verification 三态 + 12 个共用错误码),本项目只补它们做不了的四件事: 能力并集、按 op 路由、在信封里补一格 provenance(谁算的、跑在哪个 runtime / 架构)、 把两端的 latex 印刷统一到 sympy 的打印机(\arctan{\left(x \right)}、运算符两侧空格、无裸 atan)。 契约按「输入 WL,输出看 latex」用:wl 是引擎自己的书写,跨引擎不可比。

调用方把 SYMPY_URL 换成网关地址,程序一个字不用改。理由、差异清单、判定顺序见 docs/gateway-schema.md。

同一份代码在 Bun 里调试,打包成单文件 worker 后交给 WinterJS。依赖用 Bun 管, .cnb.yml 在进开发环境前把工具链和依赖装好。

快速开始

bun install

bun run dev      # http://127.0.0.1:8787,改 src/ 自动重打并重启(改 src/site 会先 astro build)
bun test         # 257 条 / 19 个文件;其中 78 条联网(sympy 56 + symbolica 22),未配上游地址时跳过
                 # 静态页那 12 条依赖 dist/site:构建过才真跑,否则 skip(顺序见 docs/test-coverage.md §5)
bun run build    # rm -rf dist/site → astro build → 打包成 dist/worker.js(约 1.3 MB)

bun run wasmer   # build 后用真 runtime 跑:wasmer/winterjs@1.2.0,端口 8080

# 网关的三条接口(未配上游时:能力表为空、evaluate 一律 422 op_unroutable)
curl -s localhost:8787/v1/capabilities
curl -s localhost:8787/healthz
curl -s -XPOST localhost:8787/v1/evaluate \
     -H 'content-type: application/json' \
     -d '{"op":"integrate","expr":"x^2"}'

cp .env.example .env   # 填 SITE_URL(构建期出 sitemap 用)
bun run deploy         # 读 .env → build → wasmer deploy(需 WASMER_TOKEN)

变量

三地址即可跑通:SITE_URL(本站域名,构建期)+ SYMBOLICA_URL / SYMPY_URL(两个上游, 期)。上游地址只从环境读并在构建期注入产物——域名可能带 token,不进仓库;缺哪个,哪个后端的 op 就回 422 op_unroutable(合法状态,不是错误配置)。

cp .env.example .env   # 模板里的注释就是说明书

规矩、优先级、排错见 docs/env.md。可选开关只有 WASMER_APP_DOMAIN(SITE_URL 兜底)、BASE_PATH(子路径)、SYM_VERSION(调版本回显)、WASMER_TOKEN(部署凭证,云原生 开发已注入)。BASE_PATH 只管静态资源前缀;API 路径不变,/sym/healthz 仍需部署层改写。

目录

src/app.js               装配:API 优先(闭集),其余查静态表
src/gateway.js           网关四条路由 + 判定顺序 + 上游故障四态
src/envelope.js          统一错误信封(两端的逐字拷贝)+ request_id
src/schema/contract.js   协议真源:字段 / 限额 / 码表 / 上游表 / 路由判据
src/schema/request.js    请求闭集解析(未知键 / 缺字段 / 值域,各自给 detail)
src/upstream/client.js   转发:35 s 预算、连不上 vs 答了、透传不改写
src/upstream/capabilities.js  能力并集:可达性与能力分开报,冲突留痕
src/version.js           包版本(构建期 define,跑源码时读 package.json)
src/static.js            静态资源表:查表 + 本地读盘兜底
src/worker.js            WinterCG 入口,注册 fetch 事件
src/winterjs-compat.js   WinterJS 的 Response 兼容补丁(关键,见 docs/winterjs.md)
src/site/content/docs/   Starlight 页面(Markdown/MDX,构建期出 HTML)
src/site/content.config.ts docs 集合(docsLoader + docsSchema)
astro.config.mjs         Astro/Starlight 配置(srcDir/outDir/site/base/侧边栏)
scripts/build.mjs        loadEnv → cleanSite → astro build → 收集产物 → Bun.build 单文件 worker
scripts/env.mjs          读 .env(空值视为未设置;给 astro 子进程传 --env-file)
scripts/deploy.mjs       读 .env → build → wasmer deploy,域名只需配一次
scripts/astro.mjs        cleanSite(rm -rf dist/site)+ 产物收集(base64 内联)
scripts/serve.mjs        Bun.serve 模拟 worker 环境
scripts/dev.mjs          fs.watch + 重启,site 变动先重建静态页
scripts/install-bun.sh   装 bun(钉 1.4.4,走 GitHub release + sha256)
scripts/install-wasmer.sh装 wasmer cli(钉 7.4.0,原因见 docs/toolchain.md)
test/                    bun test
wasmer.toml              Wasmer 包清单
app.yaml                 Wasmer Edge 应用清单
.cnb.yml                 云原生开发环境

云原生开发

.cnb.yml 只有一条 vscode 流水线:分支页点「云原生开发」时启动,stages 在进 IDE 之前跑完。

项值
触发vscode(页面「云原生开发」按钮)
环境默认开发环境 cnbcool/default-dev-env(不声明 docker 即默认镜像)
服务vscode(单容器,WebIDE + VSCode Remote-SSH)
资源runner.cpus: 2(2 核 / 4 GiB)
密钥imports 引用 Tomori0Nao/TOKENS 的 wasmer/env.dev.yml(注入 WASMER_TOKEN)
stages[0] toolchain   jobs 对象 → 两路并行
  ├─ install bun          scripts/install-bun.sh
  └─ install wasmer       WASMER_VERSION=7.4.0 scripts/install-wasmer.sh
stages[1] deps        bun install --frozen-lockfile
stages[2] verify      wasmer --version + bun test + bun run build(allowFailure)

三个语法点,写错就静默失效:

  • jobs 数组 = 串行,jobs 对象 = 并行;stages 之间永远串行。
  • bun install 不能和「装 bun」并行——它用的就是刚装到 /usr/local/bin 的 bun,不是镜像自带的。
  • 每个 stage 是新 shell,/etc/profile.d 不保证被读到,所以 deps / verify 里显式补 PATH。

imports 读的是文件:必须写到 wasmer/env.dev.yml 这一级且用 /-/blob/。/-/tree/ 是目录页、 /-/raw/ 会被判 Invalid file resource。密钥仓库默认只允许负责人/管理员触发的流水线引用, 放开要写 allow_slugs + allow_events(含 vscode,只写 push 读不到)。

版本

组件版本说明
bun1.4.4见 docs/toolchain.md
hono4.13.14唯一运行时依赖
astro7.4.4只做构建期静态产出,不进 worker
@astrojs/starlight0.42.8站点主题,与 rs-site-tools 同款;0.41+ 要 Astro 7
@astrojs/sitemap3.7.4配了 SITE_URL 才启用;跟 astro 7 同代(都用 zod/v4)
wasmer cli7.4.07.4.1+ 要 glibc 2.38,默认镜像只有 2.36
wasmer/winterjs1.2.0模块名是 winterjs,不是子命令 serve

接口

方法 + 路径做什么
POST /v1/evaluate求解。op 决定去哪:integrate → symbolica,其余 25 个 → sympy
GET /v1/capabilities两边 ops 的并集(现拉现并),每个 op 标出 upstream
GET /healthz网关自身 + 每个上游的 reachable / ready / engine / version;?deep=1 才真打上游
GET /服务信息;静态站建过就出首页(平台的就绪探测打这里)

错误统一 {request_id, error:{code, message, detail}}:12 个共用码 + 上游的 503 engine_unavailable / 504 timeout(原样透传)+ 网关自产的 422 op_unroutable。

文档

文件内容
docs/gateway-schema.md两端协议对账、网关加的四样(含 latex 规范化)与刻意不加的四样、判定顺序、故障四态
docs/astro-integration.md方案对比、Starlight 主题、构建两段式、三处硬细节、路由
docs/cnb-pipeline.md.cnb.yml 逐段解释、并行/顺序的判据、密钥接入
docs/winterjs.mdc.json() 在 WinterJS 上 500 的根因、补丁、打包 target
docs/toolchain.mdbun / wasmer 的版本钉法与 glibc 分界、脚本做了什么
docs/deploy.mdwasmer.toml 三处不能省、本地跑真 runtime、部署流程
docs/env.md三个地址(本站 + 两上游)、.env 的优先级与空值语义、谁在读它
docs/verification.md一次部署 + 经网关验证的记录、修掉的五个运行时差异、冷启动与已知限制
docs/test-coverage.md257 条用例的覆盖矩阵、公式语料格式(每 op 简单+复杂各一条)、归一化比对规则、剩余缺口
docs/site-audit.md站点内容核对记录:4 处与线上不符、示例页形态、HEAD 500、构建告警

本站(bun run wasmer 后访问 /)只写给调用方看的东西,不写实现内幕:

路径内容
/一句话说清是什么 + 三条必知规矩
/guide/start一次 curl、换语言怎么调、HTTP 状态分三类
/api端点、五个请求键、五段信封、26 个 op 两组
/api/response逐字段,以及「200 但没有答案」的三种情况
/api/errors12 共用码 + 3 特殊情况码,detail 结构,上游故障四态
/api/ops26 个算子按组列全,args 含义
/examples每个算子 simple + complex 各一条可 curl 的请求与期望值

docs/ 是仓库维护视角(yaml 逐段、版本钉法、排错记录、测试口径),不上站点。 两侧讲同一件事时以 docs/ 为准,站点在它上面精简成调用方需要的最小面。

用 VSCode 连接

  1. 本地装 VSCode + Remote-SSH 插件
  2. 分支页点「云原生开发」启动环境
  3. 点页面上的 VSCode 入口按提示连接

窗口被覆盖时把 Window › New Window › Open Folders in New Window 设成 on。 想换镜像才需要写 docker.image;写了未装 code-server 的镜像会退化成双容器模式。 开发环境默认 10 分钟没心跳回收,可给 services 的 vscode 加 options.keepAliveTimeout。

文档:云原生开发 · 默认开发环境 · 流水线语法 · 文件引用与鉴权

Hono on Wasmer Edge (WinterJS / WASIX), built by Bun