@tansr/serve 0.6.0 → 0.8.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.
- package/NOTICE +59 -0
- package/README.md +113 -11
- package/dist/index.d.ts +2482 -1306
- package/dist/index.js +19166 -11222
- package/package.json +5 -3
package/NOTICE
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
NOTICE — @tansr/serve
|
|
2
|
+
=====================
|
|
3
|
+
|
|
4
|
+
Generated by `pnpm release:verify-notice --write --package server` (tansr FX-C-29, inline-declaration rule).
|
|
5
|
+
Do not edit by hand: `pnpm release:verify-notice --check` regenerates this file from the esbuild metafile and fails
|
|
6
|
+
on any difference. Every third-party package compiled into the shipped bundle is listed below, no more and no less;
|
|
7
|
+
each must carry an allow-listed license. Humans review the license column; the machine keeps the table honest.
|
|
8
|
+
|
|
9
|
+
Artifacts covered: dist/index.js
|
|
10
|
+
Runtime dependencies resolved from the consumer's node_modules (declared, not bundled): zod
|
|
11
|
+
Bundled third-party packages: 2
|
|
12
|
+
|
|
13
|
+
BUNDLED THIRD-PARTY PACKAGES
|
|
14
|
+
----------------------------
|
|
15
|
+
undici 8.10.0 | MIT
|
|
16
|
+
zod-to-json-schema 3.25.2 | ISC
|
|
17
|
+
|
|
18
|
+
LICENSE TEXTS
|
|
19
|
+
-------------
|
|
20
|
+
|
|
21
|
+
--- undici 8.10.0 (MIT) ---
|
|
22
|
+
MIT License
|
|
23
|
+
|
|
24
|
+
Copyright (c) Matteo Collina and Undici contributors
|
|
25
|
+
|
|
26
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
27
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
28
|
+
in the Software without restriction, including without limitation the rights
|
|
29
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
30
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
31
|
+
furnished to do so, subject to the following conditions:
|
|
32
|
+
|
|
33
|
+
The above copyright notice and this permission notice shall be included in all
|
|
34
|
+
copies or substantial portions of the Software.
|
|
35
|
+
|
|
36
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
37
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
38
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
39
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
40
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
41
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
42
|
+
SOFTWARE.
|
|
43
|
+
|
|
44
|
+
--- zod-to-json-schema 3.25.2 (ISC) ---
|
|
45
|
+
ISC License
|
|
46
|
+
|
|
47
|
+
Copyright (c) 2020, Stefan Terdell
|
|
48
|
+
|
|
49
|
+
Permission to use, copy, modify, and/or distribute this software for any
|
|
50
|
+
purpose with or without fee is hereby granted, provided that the above
|
|
51
|
+
copyright notice and this permission notice appear in all copies.
|
|
52
|
+
|
|
53
|
+
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
54
|
+
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
55
|
+
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
56
|
+
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
57
|
+
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
58
|
+
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
59
|
+
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
package/README.md
CHANGED
|
@@ -115,9 +115,16 @@ const v2: AgentSessionsOptions = {
|
|
|
115
115
|
`reason?`(contract-v0.21 / RFC-SC-1)= 终局帧 `TerminalReason` 原值,单帧区分
|
|
116
116
|
`client_gone`(订阅者离场被策略止损)/ `internal_error`(内核故障)/ 用户中断
|
|
117
117
|
`aborted_*` 等,接收方按「已知值专项 + 未知值兜底」消费;
|
|
118
|
-
- **签名**:`secret` 在场时携 `x-tansr-signature:
|
|
119
|
-
(`TURN_END_NOTIFY_SIGNATURE_HEADER`
|
|
120
|
-
|
|
118
|
+
- **签名**:`secret` 在场时携 `x-tansr-signature: v2=<hex>, v1=<hex>`
|
|
119
|
+
(`TURN_END_NOTIFY_SIGNATURE_HEADER`;FX-C-43 双签一版,`signatureVersions`
|
|
120
|
+
缺省 `['v2','v1']`):`v2` = protocol `WEBHOOK_SIGNATURE_V2` canonical(随行
|
|
121
|
+
`x-tansr-timestamp` / `x-tansr-nonce`),`v1` = 对原始请求体全文 HMAC-SHA256——
|
|
122
|
+
接收端先验签再消费(tansrd 缺省只收 v2);
|
|
123
|
+
- **CLI 形态两键(FX-C-09/续)**:`tansr serve --v2` 以 `TANSR_SERVE_NOTIFY_URL`
|
|
124
|
+
(绝对 http(s) URL)/ `TANSR_SERVE_NOTIFY_SECRET` 两 env 接同一缝(见下文旋钮表
|
|
125
|
+
`notify` 组)——**无 URL = 不出站**;secret 单独在场忽略并告警;启动期 stdout 一行
|
|
126
|
+
只打 URL 的 origin 与「签名在场 / 缺席」,secret 与路径 / 查询串恒不打印;未开 `--v2`
|
|
127
|
+
时两键列入「仅对 /v2 宿主生效」告警;
|
|
121
128
|
- **投递纪律**:fire-and-forget 恒不阻断会话主链;2xx 即成功,否则指数退避
|
|
122
129
|
重试(缺省 1+2 次,`V2_LIMITS.notifyMaxRetries/notifyTimeoutMs/notifyBackoffMs`
|
|
123
130
|
可覆写);终败走 `onDeliveryFailure` 结构化通报;服务器优雅关闭期恒不出站;
|
|
@@ -221,6 +228,15 @@ process.on('SIGINT', shutdown);
|
|
|
221
228
|
Ctrl+C(SIGINT)收束,Linux/容器上两枚都会到;
|
|
222
229
|
- **与 `onTurnEndNotify` 的关系**:优雅关闭期出站通知恒不发(见上文投递纪律),
|
|
223
230
|
客户端靠回连 `Last-Event-ID` / history / resume 追赶。
|
|
231
|
+
- **进程级兜底(十王修案 FX-C-02)**:引擎恒不替你挂 `unhandledRejection` / `uncaughtException`
|
|
232
|
+
监听,但导出 `installProcessGuards({ logger, onFatal, drain?, drainTimeoutMs? })`(返回卸载函数)
|
|
233
|
+
供宿主入口**安装一次**:任何逃逸到进程级的拒绝 / 异常恒记一条结构化事件
|
|
234
|
+
`process.unhandled_rejection` / `process.uncaught_exception{ origin, message, stack(≤ 2 KB), policy }`
|
|
235
|
+
(旧形 logger 回落 i18n 文案行);`onFatal:'drain-exit'` = 记完 → `drain()`(有界,缺省 10 s)→
|
|
236
|
+
`exit(1)`(多租常驻进程缺省:`tansr serve` / serve-v2 参考宿主 / tansrd);`'log'` = 记完继续
|
|
237
|
+
(单用户入口缺省:acp / mcp serve / headless / serve-demo)。env `TANSR_SERVE_ON_UNHANDLED=log|drain-exit`
|
|
238
|
+
经 `resolveServeRuntimeOptions(env).onUnhandled` 翻转;路由层错误边界(SC-01)与建会临界区
|
|
239
|
+
(FX-C-01)是第一道,这是最后一道——不是替代品。
|
|
224
240
|
|
|
225
241
|
完整可跑示例见仓内 `examples/serve-demo/server.ts`(接线封装在 `examples/serve-demo/runtime.ts`)。
|
|
226
242
|
|
|
@@ -255,10 +271,69 @@ const server = await startServer({
|
|
|
255
271
|
纪律(doc/118 §八 G5/G9 代拍):**任一变量缺席/空串即不落键 → 未设 = 库缺省,行为零漂移**;
|
|
256
272
|
非法值(非整数、越界、枚举外)进 `warnings` 由宿主一行告警后忽略,恒不拒启;`applied` 列出生效
|
|
257
273
|
的变量名,`appliedRuntimeEnvByGroup(runtime, 'governance', 'v2')` 可判某些组是否在场(CLI `tansr serve`
|
|
258
|
-
|
|
259
|
-
`
|
|
260
|
-
|
|
261
|
-
`
|
|
274
|
+
缺省是 /v1 面,治理五键与分片码在场即提示无效;`tansr serve --v2` / `TANSR_SERVE_V2=1` 起挂 /v2 单运维方形
|
|
275
|
+
——同一 Bearer token + `x-tansr-end-user` 头分域、store 落 `<sessionsDir>/agent-v2/`、`cwdPolicy` = 启动 cwd 子树,
|
|
276
|
+
此时这些键有消费点;FX-C-46,doc/98 §十 2026-09-08 行)。建议值与部署口径见 `deploy/serve-v2/README.md` §三 与
|
|
277
|
+
`deploy/serve-v2/.env.example`;全表由 `runtime-options.ts` 的 `SERVE_RUNTIME_ENV` **表生成**如下(FX-C-41,
|
|
278
|
+
doc/130 R-12 生成律:`pnpm env:example` 再生、`pnpm docs:check` 幂等门;同一张表还生成
|
|
279
|
+
`packages/server/.env.example`,`pnpm env:check` 锁住;`process` 组的 `TANSR_SERVE_ON_UNHANDLED` →
|
|
280
|
+
`installProcessGuards({ onFatal })`,见上节「进程级兜底」;`factory` 组三键 →
|
|
281
|
+
`createAgentSessionFactory({ ...runtime.factory })` 顶层键,语义见表后一段):
|
|
282
|
+
|
|
283
|
+
<!-- env:begin -->
|
|
284
|
+
<!-- 由 packages/server/src/runtime-options.ts 的 SERVE_RUNTIME_ENV 表生成(FX-C-41):`pnpm env:example` 再生,`pnpm docs:check` 幂等门;手改本区段会被门打回 -->
|
|
285
|
+
|
|
286
|
+
全表 **30 键**(键序 = 表声明序;缺席 / 空串 = 库缺省,非法值忽略并告警):
|
|
287
|
+
|
|
288
|
+
| 变量 | 组 | 目标选项 | 形态 | 约束 | 单位 |
|
|
289
|
+
|---|---|---|---|---|---|
|
|
290
|
+
| `TANSR_SERVE_MAX_ACTIVE_SESSIONS` | `admission` | `admission.maxActiveSessions` | int | integer >= 1 | — |
|
|
291
|
+
| `TANSR_SERVE_MAX_SSE_CONNECTIONS` | `admission` | `admission.maxSseConnections` | int | integer >= 1 | — |
|
|
292
|
+
| `TANSR_SERVE_MAX_INFLIGHT_BODY_BYTES` | `admission` | `admission.maxInflightBodyBytes` | int | integer >= 1 | bytes |
|
|
293
|
+
| `TANSR_SERVE_ELD_THRESHOLD_MS` | `admission` | `admission.eventLoopDelayP99Ms` | int | integer >= 1 | ms |
|
|
294
|
+
| `TANSR_SERVE_REQUEST_TIMEOUT_MS` | `http` | `http.requestTimeout` | int | integer >= 0 | ms |
|
|
295
|
+
| `TANSR_SERVE_EXPOSE_OBSERVABILITY` | `observability` | `observability.expose` | bool | 1\|true\|yes\|on / 0\|false\|no\|off | — |
|
|
296
|
+
| `TANSR_SERVE_EXPOSE_METRICS` | `observability` | `observability.exposeMetrics` | bool | 1\|true\|yes\|on / 0\|false\|no\|off | — |
|
|
297
|
+
| `TANSR_SERVE_EVENT_BUFFER_MAX_BYTES` | `ring` | `eventBufferMaxBytes` | int | integer >= 1 | bytes |
|
|
298
|
+
| `TANSR_SERVE_ORPHAN_GRACE_MS` | `governance` | `v2.governance.orphanGraceMs` | int | integer >= 0 | ms |
|
|
299
|
+
| `TANSR_SERVE_IDLE_AFTER_GONE_MS` | `governance` | `v2.governance.idleAfterGoneMs` | int | integer >= 0 | ms |
|
|
300
|
+
| `TANSR_SERVE_MAX_RETAINED_SESSIONS` | `governance` | `v2.governance.maxRetainedSessions` | int | integer >= 0 | — |
|
|
301
|
+
| `TANSR_SERVE_MAX_SESSION_LIFETIME_MS` | `governance` | `v2.governance.maxSessionLifetimeMs` | int | integer >= 1 | ms |
|
|
302
|
+
| `TANSR_SERVE_MAX_TURNS_PER_SESSION` | `governance` | `v2.governance.maxTurnsPerSession` | int | integer >= 1 | — |
|
|
303
|
+
| `TANSR_SERVE_SESSION_SHARD` | `v2` | `v2.sessionIdShard` | int | integer in [0, 255] | — |
|
|
304
|
+
| `TANSR_SERVE_NOTIFY_URL` | `notify` | `v2.onTurnEndNotify.url` | string | absolute http(s) URL | — |
|
|
305
|
+
| `TANSR_SERVE_NOTIFY_SECRET` | `notify` | `v2.onTurnEndNotify.secret` | **secret** | non-empty string; value never logged; requires TANSR_SERVE_NOTIFY_URL | — |
|
|
306
|
+
| `TANSR_SERVE_UPSTREAM_MAX_INFLIGHT` | `upstream` | `governor.bulkhead.maxConcurrent` | int | integer >= 1 | — |
|
|
307
|
+
| `TANSR_SERVE_UPSTREAM_CONNECT_TIMEOUT_MS` | `session` | `session.timeouts.connectTimeoutMs` | int | integer >= 1 | ms |
|
|
308
|
+
| `TANSR_SERVE_UPSTREAM_IDLE_TIMEOUT_MS` | `session` | `session.timeouts.idleTimeoutMs` | int | integer >= 1 | ms |
|
|
309
|
+
| `TANSR_SERVE_UPSTREAM_TOTAL_TIMEOUT_MS` | `session` | `session.timeouts.totalTimeoutMs` | int | integer >= 1 | ms |
|
|
310
|
+
| `TANSR_SERVE_TURN_WALL_CLOCK_MS` | `session` | `session.maxTurnWallClockMs` | int | integer >= 1 | ms |
|
|
311
|
+
| `TANSR_SERVE_SSE_MAX_BUFFER_BYTES` | `sse` | `sse.maxBufferBytes` | int | integer >= 1 | bytes |
|
|
312
|
+
| `TANSR_SERVE_SSE_SLOW_POLICY` | `sse` | `sse.onSlowSubscriber` | enum | disconnect\|drop-oldest | — |
|
|
313
|
+
| `TANSR_SERVE_SSE_RETRY_MS` | `sse` | `sse.retryMs` | int | integer >= 0 | ms |
|
|
314
|
+
| `TANSR_SERVE_LOG_FORMAT` | `log` | `logger.log` | enum | json\|text | — |
|
|
315
|
+
| `TANSR_SERVE_ON_UNHANDLED` | `process` | `processGuards.onFatal` | enum | log\|drain-exit | — |
|
|
316
|
+
| `TANSR_SERVE_READY_STREAM` | `process` | `readyFrame` | enum | stdout\|stderr\|none | — |
|
|
317
|
+
| `TANSR_SERVE_CWD_ON_RESUME` | `factory` | `factory.cwdOnResume` | enum | current\|stored | — |
|
|
318
|
+
| `TANSR_SERVE_SESSION_MAX_AGE_DAYS` | `factory` | `factory.sessions.retention.maxAgeDays` | int | integer >= 1 | days |
|
|
319
|
+
| `TANSR_SERVE_SESSION_MAX_PER_END_USER` | `factory` | `factory.sessions.retention.maxPerEndUser` | int | integer >= 1 | — |
|
|
320
|
+
|
|
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`。
|
|
322
|
+
<!-- env:end -->
|
|
323
|
+
|
|
324
|
+
`factory` 组三键语义(表内只列形态与约束):`TANSR_SERVE_CWD_ON_RESUME=current|stored` → `cwdOnResume`,
|
|
325
|
+
resume 时存储 cwd ≠ 本次的处置——配了 `cwdPolicy` 的宿主缺省 `stored`(存储值重过策略闸,
|
|
326
|
+
策略拒 / 目录已失 → 409 `cwd_unavailable{detail.reason}`),未配缺省 `current`;`current` = 一键回退,十王修案 FX-C-08;
|
|
327
|
+
`TANSR_SERVE_SESSION_MAX_AGE_DAYS` / `TANSR_SERVE_SESSION_MAX_PER_END_USER` → `sessions.retention.{maxAgeDays,maxPerEndUser}`,
|
|
328
|
+
会话保留期(十王修案 FX-C-09 / C2-04):**两者皆缺席 = 零删除 = 现状永存**;任一在场即启用治理扫描第 ⑤ 段「store 保留」——
|
|
329
|
+
每 sweep 周期经工厂 `sweepRetention` 触发、实扫间隔缺省 1 h,按 store `meta.updatedAt` 删超龄(`maxAgeDays` 缺席按 30 d 兜底,
|
|
330
|
+
与 api 会话租约窗同值;**M-05**:平台内置形装配过的 endUser 域以其 bundle `governance.sessionRetentionDays`(控制台 org 治理配置)
|
|
331
|
+
覆写该域超龄阈值,缺键域沿兜底;**落盘(FX-C-09 收官)**:该天数随建档写入会话 `meta.json` 的 `retentionDays`(resume 再装配后对账),
|
|
332
|
+
扫描逐会话优先按它判龄,serve 重启后零回退——收官前建的无键旧会话仍按兜底)/ 每 endUser 超数最旧的会话记录(附件 / 同居快照 / 独立根快照同删;在册活跃会话恒不删),
|
|
333
|
+
每轮有删除即记 `session.retention_swept{scanned,deleted,failures,byReason}`;程序面另有 `maxBytes` / `sweepIntervalMs`
|
|
334
|
+
与手动 `build.sweepSessionRetention({ force:true })`。
|
|
335
|
+
|
|
336
|
+
不在表内(语义归各自入口):`TANSR_SERVE_TOKEN`(/v1 Bearer)、
|
|
262
337
|
`TANSR_SERVE_DRAIN_TIMEOUT_MS`(drain 超时,缺省 30 s)、`TANSR_SERVE_V1_RETENTION_MS` /
|
|
263
338
|
`TANSR_SERVE_V1_MAX_RETAINED`(SC-18)、`TANSR_SERVE_MCP_CONNECTIONS`(SC-31;缺省 1、上限 16。
|
|
264
339
|
**SC-44 起只是进程级兜底层**:`mcpServers.<name>.pool.connections` 逐台键 > 程序面 `pool` 选项 > 本 env
|
|
@@ -292,7 +367,15 @@ NetworkPolicy);`deploy/serve/` 是 CLI `tansr serve` /v1「一容器一智能体
|
|
|
292
367
|
(缺省 30 s,到点 `interrupt()`,轮末 store 提交照走)→ flush 落盘 → 停监听 ≤ 5 s + 连接收口 ≤ 5 s →
|
|
293
368
|
宿主 `governor.close()` → exit 0;t0+45 s 未退出 → SIGKILL。宽限恒 ≥ drain 超时 + 15 s。
|
|
294
369
|
- **观测端点暴露**:容器绑 `0.0.0.0` 时须 `TANSR_SERVE_EXPOSE_OBSERVABILITY=1`(参考镜像已设),探针
|
|
295
|
-
与抓取器走内网直连副本;反代恒不把 `/metrics` `/healthz` `/readyz`
|
|
370
|
+
与抓取器走内网直连副本;反代恒不把 `/metrics` `/healthz` `/readyz` 转到公网。十王修案 FX-C-42(O-5):
|
|
371
|
+
`TANSR_SERVE_EXPOSE_METRICS` 单独控 `/metrics`(优先于总开关);CLI `tansr serve` 入口把 `/healthz` `/readyz`
|
|
372
|
+
钉为**恒开**(探针面无机密,父进程 tansrd 池 / K8s 探活不受 `EXPOSE_OBSERVABILITY=0` 影响),库形态仍按
|
|
373
|
+
`exposeHealth` / `exposeMetrics` / `expose` 三选项自定。
|
|
374
|
+
- **进程间就绪帧**(FX-C-42;S2-04 / 候拍 ㉑):listening 后引擎恒额外写一行 `TANSR_READY {"v":1,"url":"http://127.0.0.1:1234","pid":4242,"readyz":"/readyz"}`
|
|
375
|
+
到 stdout——它**不是日志**(不经 `ServeLogger`、不受 `TANSR_SERVE_LOG_FORMAT` 影响、无 ts / level),是父子进程
|
|
376
|
+
协议(tansrd 池 `readyFrom` 第 ① 形;② `server.listening` JSON 行 / ③ 文案行为兜底,旧 serve 兼容一版)。
|
|
377
|
+
日志采集器按行严格 JSON 解析时 `TANSR_SERVE_READY_STREAM=stderr` 改道,嵌入式宿主 `readyFrame:'none'` 或
|
|
378
|
+
传写函数自定;`formatReadyFrame` / `parseReadyFrame` 是帧的唯一形态源(两端同笔)。
|
|
296
379
|
- **容量估算**(本机现状档不外推;doc/118 §一-1.1):单进程 ≈2500 活跃 SSE 连接时 ELD p99 ≈190 ms、
|
|
297
380
|
5000 连接 ≈250 ms;≈35 KiB 堆/会话(全装配链);企业档参考帽 `maxActiveSessions 5000` /
|
|
298
381
|
`maxSseConnections 10000` / `maxInflightBodyBytes 256 MiB` / ELD p99 200 ms(G5,仅文档)。
|
|
@@ -432,10 +515,14 @@ serve 层:`tansr_serve_http_requests_total{method,route,status}`(route 恒模板
|
|
|
432
515
|
`tansr_serve_event_loop_delay_ms{stat=p50|p99|max}`(两次采集之间的窗口)、
|
|
433
516
|
`process_resident_memory_bytes`、`tansr_serve_webhook_deliveries_total{result}`、
|
|
434
517
|
`tansr_serve_store_commit_errors_total` / `tansr_serve_store_create_errors_total`、
|
|
435
|
-
`tansr_serve_token_mint_failures_total
|
|
518
|
+
`tansr_serve_token_mint_failures_total`、`tansr_serve_token_invalidations_total{reason}`(FX-C-15:上游 401
|
|
519
|
+
裁定令牌失效,按信封 `detail.reason` 分键;每次伴随失效 + 重铸 + 重试恰一次)。
|
|
436
520
|
|
|
437
521
|
纪律:指标标签**恒不含** sessionId / endUserId / 令牌 / 消息内容(高基数与凭据禁令);
|
|
438
|
-
未知路径一律 `route="other"
|
|
522
|
+
未知路径一律 `route="other"`。`/v2` 的 `route` 模板与路由分发同出一表 `V2_ROUTE_TABLE`(导出;21 端点 ×
|
|
523
|
+
`{ method, action(模板), pattern, endpoint }`,FX-C-45)——此前观测层手写 7 动作,compact / checkpoints 全族 /
|
|
524
|
+
cwd / audio 九条路径落 `other`;今 `other` 只对域内 404 出现(锁卷 `observability-route-coverage.test.ts`)。
|
|
525
|
+
同进程起多台 `startServer` 且共享缺省注册表时,gauge 族由最后
|
|
439
526
|
采集者覆写、counter 族累加——需按实例隔离读数时各传 `observability.metrics: createMetricsRegistry()`。
|
|
440
527
|
|
|
441
528
|
### 结构化日志与 request-id
|
|
@@ -498,7 +585,16 @@ build.upstreamStats?.(); // { tokenMinter: { inflight, queued, mints,
|
|
|
498
585
|
- **铸令牌闸 / 抖动 / 负缓存**:500 endUser 同时首连时 `/v1/app-tokens` 在飞峰值 = 闸值(此前 500);
|
|
499
586
|
同批铸出的令牌不再同刻进入刷新窗;某 endUser 铸造失败后窗内不再出网(直接回同一错),
|
|
500
587
|
刷新失败但旧令牌仍在时效内直接沿用旧令牌;`warm(endUserIds)` 可在启动期预热。
|
|
501
|
-
-
|
|
588
|
+
- **令牌失效反馈(十王修案 FX-C-15 / R-02)**:平台对携 `x-tansr-app-token` 的请求(模型 exchange / bundle /
|
|
589
|
+
平台工具)回 `401 { error: { code: 'unauthorized', detail: { reason } } }` 时,刷新 fetch 在**同一请求内**
|
|
590
|
+
`minter.invalidate`(仅当缓存现值仍是本次所携令牌)→ 重铸 → 重发**恰一次**;重试仍 401 则原样交回(每请求至多
|
|
591
|
+
一次重铸,恒不循环)。`reason === 'check_unavailable'`(平台校验依赖瞬态不可用)不失效、不重铸;其余码 /
|
|
592
|
+
403 / 无信封亦不触发。此前吊销令牌后 serve 拿旧令牌 ≈ 55 min 恒 401。计数:`stats().invalidations{reason}`
|
|
593
|
+
(只计真正逐出)+ 指标 `tansr_serve_token_invalidations_total{reason}`(按 401 裁定计;自实现 minter 缺
|
|
594
|
+
`invalidate` 时只计不重试)。失效码集合 `TOKEN_INVALIDATING_CODES = ['unauthorized']`(导出;M-13 起改由
|
|
595
|
+
openapi `x-invalidates-token` 生成到 sdk,serve import)。
|
|
596
|
+
- **bundle 缓存**:键 `(apiBaseUrl, appId, scope, featuresFingerprint)`(FX-C-16:径别 `app_user` | `owner` + 客户端
|
|
597
|
+
features 声明指纹;serve 恒令牌径,宿主自有 owner 径消费方共享同一实例亦不串档),TTL = min(平台 `max-age`, `bundleCacheTtlMs`);过期后
|
|
502
598
|
`If-None-Match` 条件重拉(304 只续期);features(heartbeat)按 endUser 每 TTL 一次而非每会话。
|
|
503
599
|
建会话上游往返:冷 endUser 3 → 1(仅铸令牌;首次 +1 config),热 endUser 2 → 0。
|
|
504
600
|
**一致性 SLA**:控制台改模型授权/别名后在网关生效的延迟上界 = `bundleCacheTtlMs`(缺省 60 s);
|
|
@@ -518,3 +614,9 @@ build.upstreamStats?.(); // { tokenMinter: { inflight, queued, mints,
|
|
|
518
614
|
- **G3 平台限流上报**:平台现行限流键绑 app key(`/t1/exchange` 120/min)+ 源 IP(600/min);网关形态
|
|
519
615
|
下全部 endUser 共用一把 key、一个出口 IP,本节的闸/缓存只能削峰、不能抬顶——`upstream_unavailable`
|
|
520
616
|
持续出现且 `Retry-After` 对齐到分钟整点,即触顶信号,应上报平台侧调档(总卷 G3 / C 路 D-1)。
|
|
617
|
+
|
|
618
|
+
## 应用系统提示词与移动端(AP-SP)
|
|
619
|
+
|
|
620
|
+
平台内置形的 `platform.system` 为宿主业务段;未设置时使用平台应用 `systemPrompt`。默认 `fallback` 下显式值(含 `[]`)替换平台段;平台 `systemPromptPolicy=prepend` 时保留平台段在前,再拼宿主段,`[]` 也不会移除平台段。`platform.systemAppend` 追加宿主工具使用指南,不触发覆盖。P 与 S 是同一 system 层输入,拼接不是权限或冲突裁决机制。
|
|
621
|
+
|
|
622
|
+
Android/iOS 经 `/v2` 连接本服务,用户 `prompt` 不是 system 字段;配置放在平台或 Node 宿主,客户端不传 appkey。平台保存正文或策略后,已有会话在下一轮开始前按 ETag 验证配置,绕过 60 秒装配缓存;会话历史继续保留,正在执行的一轮(含工具多步)使用该轮提示词快照。宿主 S/A 仍在建会时固定;恢复历史不阻止下一轮刷新。刷新失败会以 `application_prompt_refresh_failed` 和 `turn.aborted` 中止本轮,不带旧配置发起模型调用;刷新默认最多等待 30 秒,可取消后重试。工具、权限、模型和计价等其他配置仍沿原装配生命周期。示例及完整矩阵见 [serve-demo](../../examples/serve-demo/README.md) 与 [提示词指南](https://docs.tansr.com/sdk/system-prompts/)。此变更尚需正式发布包含 AP-SP 的版本。
|