@tansr/serve 0.3.2 → 0.5.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/dist/index.d.ts CHANGED
@@ -4207,6 +4207,7 @@ declare const CONTROL_FRAME: {
4207
4207
  readonly permissionClosed: "server.permission.closed";
4208
4208
  readonly questionRequest: "server.question.request";
4209
4209
  readonly questionClosed: "server.question.closed";
4210
+ readonly platformWarning: "server.platform.warning";
4210
4211
  };
4211
4212
  type ControlFrameName = (typeof CONTROL_FRAME)[keyof typeof CONTROL_FRAME];
4212
4213
  /** 判别一个流内条目是否控制帧(编码器/过滤器共用;gap 帧另路不经此判) */
@@ -4244,6 +4245,14 @@ interface PermissionRequestPayload {
4244
4245
  interface RequestClosedPayload {
4245
4246
  requestId: string;
4246
4247
  }
4248
+ /**
4249
+ * server.platform.warning 载荷(平台 t.warn 同形投影;恒不代表请求失败,
4250
+ * 回答照常——仅结构化告知非致命降级,呈现策略归端上)。
4251
+ */
4252
+ interface PlatformWarningPayload {
4253
+ code: string;
4254
+ message: string;
4255
+ }
4247
4256
  /** server.question.request 载荷(kernel Question 白名单拷贝) */
4248
4257
  interface QuestionRequestPayload {
4249
4258
  requestId: string;
@@ -4259,7 +4268,7 @@ interface QuestionRequestPayload {
4259
4268
  /** 仅无订阅者宽限期激活时在场(epoch_ms) */
4260
4269
  expiresAt?: number;
4261
4270
  }
4262
- type ControlFramePayload = ToolRequestPayload | ToolCancelPayload | PermissionRequestPayload | RequestClosedPayload | QuestionRequestPayload;
4271
+ type ControlFramePayload = ToolRequestPayload | ToolCancelPayload | PermissionRequestPayload | RequestClosedPayload | QuestionRequestPayload | PlatformWarningPayload;
4263
4272
  /** 出站通知 HMAC 签名头(值形 `sha256=<hex>`,对原始请求体全文签) */
4264
4273
  declare const TURN_END_NOTIFY_SIGNATURE_HEADER = "x-tansr-signature";
4265
4274
  /** 轮终局词表(KernelEvent turn.completed/turn.aborted 的投影) */
@@ -9825,6 +9834,71 @@ interface ServeSessionFactory extends SessionFactory {
9825
9834
  create(init: SessionInit, extras?: ServeSessionExtras): ServeSessionDriver;
9826
9835
  }
9827
9836
 
9837
+ interface CreateAppTokenMinterOptions {
9838
+ /** 平台 API 基址(尾斜杠归一) */
9839
+ apiBaseUrl: string;
9840
+ /** 平台「应用」公开标识(= api_keys.public_id;AK 头) */
9841
+ appId: string;
9842
+ /** 平台「应用」主密钥(SK 头 + 签名钥派生;恒不出本闭包) */
9843
+ appKey: string;
9844
+ /** 换发令牌 TTL(秒;缺省 3600,契约边界 60–86400 钳制) */
9845
+ ttlSeconds?: number;
9846
+ fetchImpl?: typeof fetch;
9847
+ now?: () => number;
9848
+ }
9849
+ interface AppTokenMinter {
9850
+ /** 取 endUserId 的现值令牌(缓存命中直返;临期/缺席铸新,在飞去重) */
9851
+ tokenFor(endUserId: string): Promise<string>;
9852
+ }
9853
+ /**
9854
+ * per-endUser app_user 令牌铸造器:appkey 双头 + TWP 签名三头(providers
9855
+ * 签名件原样复用)POST /v1/app-tokens;失败结构化上抛(状态码 + 平台错误
9856
+ * 码,恒不携凭据与令牌本体)。
9857
+ */
9858
+ declare function createAppTokenMinter(options: CreateAppTokenMinterOptions): AppTokenMinter;
9859
+ interface CreatePlatformSessionAssemblerOptions {
9860
+ minter: AppTokenMinter;
9861
+ /** 平台 API 基址(bundle 拉取与 twp 消费同基址) */
9862
+ apiBaseUrl: string;
9863
+ fetchImpl?: typeof fetch;
9864
+ /**
9865
+ * S-ARCH P2 — 平台提示帧承接(t.warn:thinking_unavailable_on_face/
9866
+ * balance_low 等;SDK onPlatformWarning 同源语义)。缺席缺省 console.warn
9867
+ * 每 (endUser, code) 一次(告知恒不静默蒸发);在场即全量接管。
9868
+ * 注:向端上(/v2 SSE)转发需新控制帧,系 doc/98 冻结面增笔——候拍,
9869
+ * 本缝先保证服务端可观测与宿主可编程。
9870
+ */
9871
+ onPlatformWarning?: (warning: {
9872
+ endUserId: string;
9873
+ sessionId: string;
9874
+ code: string;
9875
+ message: string;
9876
+ }) => void;
9877
+ }
9878
+ interface PlatformSessionAssemblerInput {
9879
+ endUserId: string;
9880
+ sessionId: string;
9881
+ /** 会话请求的模型别名(bundle aliases/目录 handle;缺省 'main') */
9882
+ model?: string;
9883
+ /**
9884
+ * S-ARCH P2(拍板 2026-09-02)— per-会话传输沉降缝:平台提示帧除宿主
9885
+ * 承接(options.onPlatformWarning)外,同帧投递本缝(工厂接 v2 控制帧
9886
+ * server.platform.warning 下发端上)。两路并行不互斥。
9887
+ */
9888
+ onWarning?: (warning: {
9889
+ code: string;
9890
+ message: string;
9891
+ }) => void;
9892
+ }
9893
+ /**
9894
+ * per-endUser 平台令牌档装配缝实现(agent-session-factory
9895
+ * assembleEndUserModel 消费):铸/取该 endUser 现值令牌 → SDK
9896
+ * assemblePlatformModel(bundle → registry;per-会话平台 ULID 经既有
9897
+ * twp sessionId 缝出线)→ 返回逐会话装配器(别名解析走 bundle registry;
9898
+ * Task 三档降档同表)。刷新 fetch 覆写令牌头,跨时效长会话自续。
9899
+ */
9900
+ declare function createPlatformSessionAssembler(options: CreatePlatformSessionAssemblerOptions): (input: PlatformSessionAssemblerInput) => Promise<SessionModelAssembler>;
9901
+
9828
9902
  /**
9829
9903
  * A 案 — 平台内置形 serve 内层工厂(用户拍板 2026-09-01:真平台装配内置
9830
9904
  * 进 serve,做实五形态边界)。
@@ -9906,6 +9980,12 @@ interface PlatformAgentSessionOptions {
9906
9980
  maxTurnsPerQuery?: number;
9907
9981
  /** runQuery 注入缝(测试脚本化;透传平台内层工厂) */
9908
9982
  runQueryImpl?: Parameters<typeof createPlatformServeSessionFactory>[0]['runQueryImpl'];
9983
+ /**
9984
+ * S-ARCH P2 — 平台提示帧承接(t.warn;透传装配缝,语义同 SDK
9985
+ * onPlatformWarning):缺席缺省 console.warn 每 (endUser, code) 一次。
9986
+ * 向 /v2 端上转发需新控制帧(doc/98 冻结面增笔),候拍不代拍。
9987
+ */
9988
+ onPlatformWarning?: Parameters<typeof createPlatformSessionAssembler>[0]['onPlatformWarning'];
9909
9989
  }
9910
9990
  interface CreateAgentSessionFactoryOptions {
9911
9991
  /**
@@ -9941,6 +10021,11 @@ interface CreateAgentSessionFactoryOptions {
9941
10021
  endUserId: string;
9942
10022
  sessionId: string;
9943
10023
  model?: string;
10024
+ /** S-ARCH P2:平台提示帧 per-会话沉降缝(工厂绑 v2 控制帧下发;自实现装配器可如实忽略) */
10025
+ onWarning?: (warning: {
10026
+ code: string;
10027
+ message: string;
10028
+ }) => void;
9944
10029
  }) => Promise<SessionModelAssembler>;
9945
10030
  }
9946
10031
  interface AgentSessionFactoryBuild {
@@ -9969,6 +10054,15 @@ declare class AgentSessionBridge {
9969
10054
  bindEmitter(emit: (type: string, payload: unknown) => void): void;
9970
10055
  /** 活跃 SSE 订阅者数通报(注册仓 → 句柄 → 本桥;提问宽限判据) */
9971
10056
  noteSubscribers(count: number): void;
10057
+ /**
10058
+ * S-ARCH P2(拍板 2026-09-02)— 平台提示帧下发:t.warn 投影为
10059
+ * server.platform.warning 控制帧(带 id 进环形缓冲,断线重放可见;旧端
10060
+ * 未知帧兜底恒安全)。emit 缝未绑定的窄窗(装配期恒无 warn)静默无害。
10061
+ */
10062
+ emitPlatformWarning(payload: {
10063
+ code: string;
10064
+ message: string;
10065
+ }): void;
9972
10066
  /** 工具调用登记(RemoteToolProxy.execute 内部调用) */
9973
10067
  registerToolCall(callId: string, name: string, args: unknown, deadlineAt: number, signal: AbortSignal): Promise<ToolResult>;
9974
10068
  /** ⑨ 回执受理(第一份有效终局;重复 409 无害) */
@@ -10000,49 +10094,6 @@ interface RemoteToolBuild {
10000
10094
  */
10001
10095
  declare function buildRemoteTool(decl: ClientToolDecl, bridge: AgentSessionBridge, now?: () => number): RemoteToolBuild;
10002
10096
 
10003
- interface CreateAppTokenMinterOptions {
10004
- /** 平台 API 基址(尾斜杠归一) */
10005
- apiBaseUrl: string;
10006
- /** 平台「应用」公开标识(= api_keys.public_id;AK 头) */
10007
- appId: string;
10008
- /** 平台「应用」主密钥(SK 头 + 签名钥派生;恒不出本闭包) */
10009
- appKey: string;
10010
- /** 换发令牌 TTL(秒;缺省 3600,契约边界 60–86400 钳制) */
10011
- ttlSeconds?: number;
10012
- fetchImpl?: typeof fetch;
10013
- now?: () => number;
10014
- }
10015
- interface AppTokenMinter {
10016
- /** 取 endUserId 的现值令牌(缓存命中直返;临期/缺席铸新,在飞去重) */
10017
- tokenFor(endUserId: string): Promise<string>;
10018
- }
10019
- /**
10020
- * per-endUser app_user 令牌铸造器:appkey 双头 + TWP 签名三头(providers
10021
- * 签名件原样复用)POST /v1/app-tokens;失败结构化上抛(状态码 + 平台错误
10022
- * 码,恒不携凭据与令牌本体)。
10023
- */
10024
- declare function createAppTokenMinter(options: CreateAppTokenMinterOptions): AppTokenMinter;
10025
- interface CreatePlatformSessionAssemblerOptions {
10026
- minter: AppTokenMinter;
10027
- /** 平台 API 基址(bundle 拉取与 twp 消费同基址) */
10028
- apiBaseUrl: string;
10029
- fetchImpl?: typeof fetch;
10030
- }
10031
- interface PlatformSessionAssemblerInput {
10032
- endUserId: string;
10033
- sessionId: string;
10034
- /** 会话请求的模型别名(bundle aliases/目录 handle;缺省 'main') */
10035
- model?: string;
10036
- }
10037
- /**
10038
- * per-endUser 平台令牌档装配缝实现(agent-session-factory
10039
- * assembleEndUserModel 消费):铸/取该 endUser 现值令牌 → SDK
10040
- * assemblePlatformModel(bundle → registry;per-会话平台 ULID 经既有
10041
- * twp sessionId 缝出线)→ 返回逐会话装配器(别名解析走 bundle registry;
10042
- * Task 三档降档同表)。刷新 fetch 覆写令牌头,跨时效长会话自续。
10043
- */
10044
- declare function createPlatformSessionAssembler(options: CreatePlatformSessionAssemblerOptions): (input: PlatformSessionAssemblerInput) => Promise<SessionModelAssembler>;
10045
-
10046
10097
  /**
10047
10098
  * /v2 装配半场 i18n 消息键(A 案下沉 2026-09-01)。
10048
10099
  *
package/dist/index.js CHANGED
@@ -37889,7 +37889,12 @@ var CONTROL_FRAME = {
37889
37889
  permissionRequest: "server.permission.request",
37890
37890
  permissionClosed: "server.permission.closed",
37891
37891
  questionRequest: "server.question.request",
37892
- questionClosed: "server.question.closed"
37892
+ questionClosed: "server.question.closed",
37893
+ // S-ARCH P2(用户拍板 2026-09-02「同意」,doc/98 §三增笔四族七名):平台
37894
+ // 提示帧下发端上——thinking_unavailable_on_face/balance_low 等非致命降级
37895
+ // 结构化告知,端侧可渲染「为什么这次没有思考」;旧端未知帧兜底恒安全
37896
+ // (Android UnknownControlFrame / iOS 同律实证)。
37897
+ platformWarning: "server.platform.warning"
37893
37898
  };
37894
37899
  var CONTROL_FRAME_NAMES = new Set(Object.values(CONTROL_FRAME));
37895
37900
  function isControlFrameType(type) {
@@ -53944,6 +53949,14 @@ var AgentSessionBridge = class {
53944
53949
  #send(type, payload) {
53945
53950
  this.#emit?.(type, payload);
53946
53951
  }
53952
+ /**
53953
+ * S-ARCH P2(拍板 2026-09-02)— 平台提示帧下发:t.warn 投影为
53954
+ * server.platform.warning 控制帧(带 id 进环形缓冲,断线重放可见;旧端
53955
+ * 未知帧兜底恒安全)。emit 缝未绑定的窄窗(装配期恒无 warn)静默无害。
53956
+ */
53957
+ emitPlatformWarning(payload) {
53958
+ this.#send(CONTROL_FRAME.platformWarning, payload);
53959
+ }
53947
53960
  // ———— 工具桥半场(RemoteToolProxy 的登记/回执面)————
53948
53961
  /** 工具调用登记(RemoteToolProxy.execute 内部调用) */
53949
53962
  registerToolCall(callId, name, args, deadlineAt, signal) {
@@ -60630,7 +60643,8 @@ async function assemblePlatformModel(options) {
60630
60643
  // S-TH3:features 能力串同缝供给(闭包定格;undefined = 门全关同现状)
60631
60644
  twp: {
60632
60645
  ...options.sessionId !== void 0 ? { sessionId: options.sessionId } : {},
60633
- features: () => features
60646
+ features: () => features,
60647
+ ...options.onWarn !== void 0 ? { onWarn: options.onWarn } : {}
60634
60648
  }
60635
60649
  });
60636
60650
  const built = buildClientFromRegistry(registry, options.model ?? "main", options.onProviderSelected);
@@ -60713,6 +60727,13 @@ function createAppTokenMinter(options) {
60713
60727
  };
60714
60728
  }
60715
60729
  function createPlatformSessionAssembler(options) {
60730
+ const warnedDefault = /* @__PURE__ */ new Set();
60731
+ const deliverWarning = options.onPlatformWarning ?? ((w) => {
60732
+ const key2 = `${w.endUserId}\0${w.code}`;
60733
+ if (warnedDefault.has(key2)) return;
60734
+ warnedDefault.add(key2);
60735
+ console.warn(`[tansr-serve] platform warning ${w.code} (endUser=${w.endUserId}): ${w.message}`);
60736
+ });
60716
60737
  return async (input) => {
60717
60738
  const initialToken = await options.minter.tokenFor(input.endUserId);
60718
60739
  const platformSessionId = ulid();
@@ -60729,7 +60750,19 @@ function createPlatformSessionAssembler(options) {
60729
60750
  baseUrl: options.apiBaseUrl,
60730
60751
  ...input.model !== void 0 ? { model: input.model } : {},
60731
60752
  fetchImpl: refreshingFetch,
60732
- sessionId: () => platformSessionId
60753
+ sessionId: () => platformSessionId,
60754
+ // S-ARCH P2:平台提示帧经 SDK onWarn 缝出线,携会话归属(serve 面
60755
+ // per-会话装配,归属天然可判——CLI 进程级电台的「无从归属」不适用此径);
60756
+ // 双路投递:宿主承接(遥测/日志)+ per-会话传输沉降(v2 控制帧)。
60757
+ onWarn: (warn) => {
60758
+ deliverWarning({
60759
+ endUserId: input.endUserId,
60760
+ sessionId: input.sessionId,
60761
+ code: warn.code,
60762
+ message: warn.message
60763
+ });
60764
+ input.onWarning?.({ code: warn.code, message: warn.message });
60765
+ }
60733
60766
  });
60734
60767
  return (alias, onProviderSelected) => {
60735
60768
  const built = buildClientFromRegistry(platform.registry, alias, onProviderSelected);
@@ -61268,7 +61301,8 @@ function createAgentSessionFactory(options) {
61268
61301
  assembleEndUserModel = createPlatformSessionAssembler({
61269
61302
  minter,
61270
61303
  apiBaseUrl: platform.apiBaseUrl,
61271
- ...platform.fetchImpl !== void 0 ? { fetchImpl: platform.fetchImpl } : {}
61304
+ ...platform.fetchImpl !== void 0 ? { fetchImpl: platform.fetchImpl } : {},
61305
+ ...platform.onPlatformWarning !== void 0 ? { onPlatformWarning: platform.onPlatformWarning } : {}
61272
61306
  });
61273
61307
  innerFactory = createPlatformServeSessionFactory({
61274
61308
  cwd: options.cwd,
@@ -61356,7 +61390,10 @@ function createAgentSessionFactory(options) {
61356
61390
  assembleOverride = await assembleEndUserModel({
61357
61391
  endUserId: init.endUserId,
61358
61392
  sessionId,
61359
- ...init.model !== void 0 ? { model: init.model } : {}
61393
+ ...init.model !== void 0 ? { model: init.model } : {},
61394
+ // S-ARCH P2(拍板 2026-09-02):平台提示帧沉降 v2 控制帧
61395
+ // server.platform.warning(桥 emit 缝绑定恒早于首轮,无丢失窗)
61396
+ onWarning: (warning) => bridge.emitPlatformWarning(warning)
61360
61397
  });
61361
61398
  }
61362
61399
  let driver;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tansr/serve",
3
- "version": "0.3.2",
3
+ "version": "0.5.0",
4
4
  "description": "Tansr agent session server: the bare /v2 agent-session protocol engine (REST + SSE) you embed in your own Node service. Session auth is fully yours via the authenticate seam. Published as @tansr/serve (decided 2026-09-01); the pack script stamps the publish name into the tarball.",
5
5
  "license": "MIT",
6
6
  "type": "module",