@tansr/serve 0.8.0 → 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +61 -10
  2. package/dist/index.d.ts +4591 -3742
  3. package/dist/index.js +3078 -1171
  4. package/package.json +1 -1
package/README.md CHANGED
@@ -32,6 +32,44 @@ npm install @tansr/serve
32
32
  (`@tansr/protocol`、`@tansr/i18n`、`@tansr/kernel`、`@tansr/providers`、
33
33
  `@tansr/sdk`)已编译内联,恒不外泄安装面。
34
34
 
35
+ ## 系统媒体工具 / System media tools
36
+
37
+ 图像生成、视频生成、语音转文字和文字转语音均由内核系统工具执行,工具名为
38
+ `ImageGen`、`VideoGen`、`SpeechToText`、`TextToSpeech`。平台内置会话工厂根据应用能力
39
+ 装配它们,并使用 SDK 的平台提供方调用授权模型;`capabilities.platform` 表示平台服务
40
+ 授权,不表示独立的“平台工具”类别。平台令牌、模型权限、配额、计费及运行时权限继续生效。
41
+
42
+ Android/iOS 经 `/v2` 会话连接时,模型与系统媒体工具运行在开发者的 serve 进程中,
43
+ 手机负责提交输入和展示真实工具事件/媒体产物,不因此取得服务端文件或终端命令权限。
44
+ 用户主动录音转写、朗读使用既有音频直连端点;它们与模型调用媒体工具并存,不自动进入聊天历史。
45
+ SDK 进程内集成仍须通过 `tools.builtin` 显式选择四媒体;这与 serve 平台工厂按应用授权装配的入口不同。
46
+
47
+ Image generation, video generation, transcription, and speech synthesis are built-in system tools.
48
+ The platform session factory assembles the authorized tools with platform-backed providers.
49
+ `capabilities.platform` retains its service-authorization meaning. On Android and iOS, these tools
50
+ run in the serve process; the mobile client renders their events and artifacts. User-triggered audio
51
+ operations use the separate direct endpoints and do not fabricate model tool events or chat history.
52
+
53
+ ## 会话元数据与开发者登录
54
+
55
+ 新构建的 `GET /v2/sessions/:id` 可返回可选的 `meta.context` 和 `meta.media`。
56
+ 前者区分下一轮/执行轮模型、真实观测用量及本地上下文预算;后者列出四类媒体的应用授权、
57
+ 模型与限制、采样时间。字段缺席表示未知,客户端不能拿累计 token 用量当作当前上下文占用。
58
+ 媒体快照是会话装配时的授权目录,实际工具是否装配及执行权限仍以服务端执行为准。
59
+ 这次没有增加 HTTP 切模端点,也没有修改已冻结的内核事件协议。
60
+
61
+ `countSpeechCharacters`、`planSpeechInput` 和相关类型从本包公开导出,用于按授权模型的
62
+ `maxChars` 校验或显式分段朗读;示例遇到尚无新出口的已发布包时会提示升级。
63
+ 开发者登录服务与平台 app_user 分离:客户端向开发者的 login/refresh 入口取短效访问票,
64
+ serve 的 `authenticate` 验证该票并返回 endUserId,平台 appkey 始终只留在服务端。
65
+ 完整远程示例见 `examples/serve-demo`;有界续期不会自动重放音频或聊天 POST。
66
+
67
+ New builds may include optional `meta.context` and `meta.media` in session metadata. Missing fields
68
+ mean unknown. Context estimates and observed billing usage are separate; the media catalog reflects
69
+ the session's assembly-time authorization. Developer login and refresh credentials remain separate
70
+ from platform app_user tokens. The public speech planner uses the authorized model's limit and explicit
71
+ segmentation; authentication recovery never automatically replays paid POST requests.
72
+
35
73
  ## 集成骨架
36
74
 
37
75
  ```ts
@@ -183,18 +221,24 @@ SSE 连接 reset、在飞轮丢、无收口日志。
183
221
  (`sse.drainRetryMs`,缺省 10 s,客户端换台后再连);② **等在飞轮**——`/v2` 运行中的
184
222
  轮至多等 `timeoutMs` 到终态,到点剩余 `interrupt()`(轮末 store 提交照走,resume 可
185
223
  续);③ **flush 落盘**——等全部 fire-and-forget 的 store 提交/建行 settle
186
- (`createAgentSessionFactory` 的 `flush`);④ **停机**——终结会话、停监听、掐空闲连接、
224
+ (`createAgentSessionFactory` 的 `flush`);④ **停机**——终结会话(**有界**:在飞 pump 至多等
225
+ `closeAllTimeoutMs`,缺省 5 s、`Infinity` 无界;到点记 `server.close_timeout{face,pending,timeoutMs}`
226
+ 后照常继续,永不 settle 的 pump 不再能挂住停机;RF-03)、停监听、掐空闲连接、
187
227
  有界等待在飞非 SSE 请求答完(≤ 5 s)再掐残余连接。回执
188
228
  `{ completedTurns, abortedTurns, flushedCommits, durationMs }` 可入日志。
189
229
  `server.close()` 保持**硬收口**语义(立即中止在飞轮、不等落盘;drain 进行中调用则等
190
230
  drain 完成);`/v1` 会话无粗态读面,drain 不等其在飞轮。
191
231
 
192
- 最小接线——两枚信号共用一个 handler,幂等位防重复进入:
232
+ 最小接线——两枚信号共用一个 handler,幂等位防重复进入;**第二枚信号不要吞掉**,应立即硬退
233
+ (运维按两次 Ctrl+C / 两次 SIGTERM 强停的习惯,吞掉 = 只能等编排器 SIGKILL):
193
234
 
194
235
  ```ts
195
236
  let stopping = false;
196
237
  const shutdown = (signal: NodeJS.Signals): void => {
197
- if (stopping) return;
238
+ if (stopping) {
239
+ console.error(`[my-service] ${signal} received again, exiting now`);
240
+ process.exit(2);
241
+ }
198
242
  stopping = true;
199
243
  console.error(`[my-service] ${signal} received, draining...`);
200
244
  server
@@ -222,10 +266,16 @@ process.on('SIGINT', shutdown);
222
266
  - **信号要能到达 node**:容器 `CMD`/`ENTRYPOINT` 用 exec 形(JSON 数组)或
223
267
  `--init`(tini 作 PID 1 转发),不要 `sh -c "node …"`(sh 当 PID 1 不转发);
224
268
  - **退出码由你定**:引擎恒不调 `process.exit`;示例里 `drain()` 成功 `exit(0)`、
225
- 失败 `exit(1)`,与你的进程监督器约定一致即可;`tansr serve`(CLI 形态)同走
226
- drain,超时经 `TANSR_SERVE_DRAIN_TIMEOUT_MS` 可配(缺省 30 s);
227
- - **Windows 注记**:`process.on('SIGTERM')` 可注册但系统不会发出;本机开发以
228
- Ctrl+C(SIGINT)收束,Linux/容器上两枚都会到;
269
+ 失败 `exit(1)`,与你的进程监督器约定一致即可;`tansr serve`(CLI 形态)订阅
270
+ SIGINT / SIGTERM / SIGHUP / SIGBREAK,首枚同走 drain(超时经 `TANSR_SERVE_DRAIN_TIMEOUT_MS`
271
+ 可配,缺省 30 s),**第二枚立即 `exit(2)`**,整链 drain 超时 + 15 s 未收口亦 `exit(2)`,
272
+ 两者都记 `process.hard_exit{signal,reason,budgetMs,elapsedMs,exitCode}`(RF-03;共享组件
273
+ `packages/cli/src/assembly/process-lifecycle.ts`);CLI 形态另把每轮墙钟缺省定为
274
+ `maxTurnWallClockMs = 1800000`(30 min;`TANSR_SERVE_TURN_WALL_CLOCK_MS=0` 停用;审查 #9)——
275
+ 库缺省仍不设,嵌入宿主自行决定;
276
+ - **Windows 注记**:`process.on('SIGTERM')` 可注册但系统不会发出、`taskkill /F` 不发任何信号;
277
+ 控制台关闭以 SIGHUP 到达且系统只留约 10 s(CLI 形态对 SIGHUP 收口预算恒 ≤ 3 s);SIGBREAK
278
+ (Ctrl+Break)与 SIGINT 同义。本机开发以 Ctrl+C(SIGINT)收束,Linux/容器上 SIGTERM / SIGHUP 都会到;
229
279
  - **与 `onTurnEndNotify` 的关系**:优雅关闭期出站通知恒不发(见上文投递纪律),
230
280
  客户端靠回连 `Last-Event-ID` / history / resume 追赶。
231
281
  - **进程级兜底(十王修案 FX-C-02)**:引擎恒不替你挂 `unhandledRejection` / `uncaughtException`
@@ -283,7 +333,7 @@ doc/130 R-12 生成律:`pnpm env:example` 再生、`pnpm docs:check` 幂等门;
283
333
  <!-- env:begin -->
284
334
  <!-- 由 packages/server/src/runtime-options.ts 的 SERVE_RUNTIME_ENV 表生成(FX-C-41):`pnpm env:example` 再生,`pnpm docs:check` 幂等门;手改本区段会被门打回 -->
285
335
 
286
- 全表 **30 键**(键序 = 表声明序;缺席 / 空串 = 库缺省,非法值忽略并告警):
336
+ 全表 **31 键**(键序 = 表声明序;缺席 / 空串 = 库缺省,非法值忽略并告警):
287
337
 
288
338
  | 变量 | 组 | 目标选项 | 形态 | 约束 | 单位 |
289
339
  |---|---|---|---|---|---|
@@ -308,6 +358,7 @@ doc/130 R-12 生成律:`pnpm env:example` 再生、`pnpm docs:check` 幂等门;
308
358
  | `TANSR_SERVE_UPSTREAM_IDLE_TIMEOUT_MS` | `session` | `session.timeouts.idleTimeoutMs` | int | integer >= 1 | ms |
309
359
  | `TANSR_SERVE_UPSTREAM_TOTAL_TIMEOUT_MS` | `session` | `session.timeouts.totalTimeoutMs` | int | integer >= 1 | ms |
310
360
  | `TANSR_SERVE_TURN_WALL_CLOCK_MS` | `session` | `session.maxTurnWallClockMs` | int | integer >= 1 | ms |
361
+ | `TANSR_SERVE_HOST_SHELL` | `session` | `session.hostShell` | enum | posix\|powershell | — |
311
362
  | `TANSR_SERVE_SSE_MAX_BUFFER_BYTES` | `sse` | `sse.maxBufferBytes` | int | integer >= 1 | bytes |
312
363
  | `TANSR_SERVE_SSE_SLOW_POLICY` | `sse` | `sse.onSlowSubscriber` | enum | disconnect\|drop-oldest | — |
313
364
  | `TANSR_SERVE_SSE_RETRY_MS` | `sse` | `sse.retryMs` | int | integer >= 0 | ms |
@@ -318,7 +369,7 @@ doc/130 R-12 生成律:`pnpm env:example` 再生、`pnpm docs:check` 幂等门;
318
369
  | `TANSR_SERVE_SESSION_MAX_AGE_DAYS` | `factory` | `factory.sessions.retention.maxAgeDays` | int | integer >= 1 | days |
319
370
  | `TANSR_SERVE_SESSION_MAX_PER_END_USER` | `factory` | `factory.sessions.retention.maxPerEndUser` | int | integer >= 1 | — |
320
371
 
321
- 分组:`admission`(4) / `http`(1) / `observability`(2) / `ring`(1) / `governance`(5) / `v2`(1) / `notify`(2) / `upstream`(1) / `session`(4) / `sse`(3) / `log`(1) / `process`(2) / `factory`(3)。同表生成的部署样例:`packages/server/.env.example`。
372
+ 分组:`admission`(4) / `http`(1) / `observability`(2) / `ring`(1) / `governance`(5) / `v2`(1) / `notify`(2) / `upstream`(1) / `session`(5) / `sse`(3) / `log`(1) / `process`(2) / `factory`(3)。同表生成的部署样例:`packages/server/.env.example`。
322
373
  <!-- env:end -->
323
374
 
324
375
  `factory` 组三键语义(表内只列形态与约束):`TANSR_SERVE_CWD_ON_RESUME=current|stored` → `cwdOnResume`,
@@ -586,7 +637,7 @@ build.upstreamStats?.(); // { tokenMinter: { inflight, queued, mints,
586
637
  同批铸出的令牌不再同刻进入刷新窗;某 endUser 铸造失败后窗内不再出网(直接回同一错),
587
638
  刷新失败但旧令牌仍在时效内直接沿用旧令牌;`warm(endUserIds)` 可在启动期预热。
588
639
  - **令牌失效反馈(十王修案 FX-C-15 / R-02)**:平台对携 `x-tansr-app-token` 的请求(模型 exchange / bundle /
589
- 平台工具)回 `401 { error: { code: 'unauthorized', detail: { reason } } }` 时,刷新 fetch 在**同一请求内**
640
+ 系统工具的平台提供方)回 `401 { error: { code: 'unauthorized', detail: { reason } } }` 时,刷新 fetch 在**同一请求内**
590
641
  `minter.invalidate`(仅当缓存现值仍是本次所携令牌)→ 重铸 → 重发**恰一次**;重试仍 401 则原样交回(每请求至多
591
642
  一次重铸,恒不循环)。`reason === 'check_unavailable'`(平台校验依赖瞬态不可用)不失效、不重铸;其余码 /
592
643
  403 / 无信封亦不触发。此前吊销令牌后 serve 拿旧令牌 ≈ 55 min 恒 401。计数:`stats().invalidations{reason}`