@acosmi/sdk-ts 2.17.0 → 2.19.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/CHANGELOG.md CHANGED
@@ -5,6 +5,36 @@ All notable changes to `@acosmi/sdk-ts` will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.19.0] - 2026-09-01 — 网关消费请求 ID 透出(跨系统关联)
9
+
10
+ **客户端的失败与上游的成功之间此前没有任何共同标识符。** 2026-08-31 事故里,GUI 上每次托管 WebSearch 都失败,而同一时刻上游 6 次搜索全部成功、6 条计费行已落库;定位花掉整场审计,因为只能靠时间戳与模型名人工对齐。网关现在把 `consumeRequestID`(即 `managed_model_usage_logs.request_id`,能 join 到计费行的那个键)放进 `X-Acosmi-Request-Id` 响应头,本版把它透出给消费方。全部改动 additive,旧调用点零改动。
11
+
12
+ ### Added
13
+
14
+ - **`GATEWAY_REQUEST_ID_HEADER`** —— 头名常量(`'X-Acosmi-Request-Id'`)。**不是**网关的传输层 `X-Request-ID`:那一个独立生成、从不写进任何计费表,两者永不相等,混用的后果是恒空 join(不报错,只是下次事故照样查不动)。
15
+ - **`GatewayRequestIDCallback`** 与四个方法的可选回调形参 —— `chatMessagesStream` / `chatStream` 第 5 形参、`chatMessages` / `chat` 第 4 形参。与既有 `onUpstreamActivity` 完全同构:旁路信号、至多触发一次、消费方回调抛错被吞掉且不中断主链路。
16
+ - 流式路径在**首字节之前**触发,因此覆盖「流中段中断」「上游 200 但零事件」「HTTP 错误」全部形态 —— 而流内事件在「事件根本没来」的场景里恰恰不存在,那正是最需要诊断的那一种。HTTP 错误响应上同样触发(错误体未必带这个 ID)。
17
+
18
+ ### 兼容性
19
+
20
+ 旧网关 + 新 SDK:回调**一次都不触发**,流照常出(fail-open)。缺失或空白的头一律按"没下发"处理,**绝不合成占位值**。
21
+
22
+ ### 回归闸门
23
+
24
+ - `test/gateway-request-id.test.ts` —— 11 例。正向对照两条:网关不下发时回调零触发(防"没头就编一个")、ID 必须在第一个事件之前到手(防退化成从流内事件取值)。另含空白头、回调抛错、HTTP 错误、不传回调时逐字兼容,以及头名与网关侧常量逐字一致、且不等于 `x-request-id` 的契约断言。
25
+
26
+ ## [2.18.0] - 2026-08-29 — `ManagedModel.thinking_levels` 类型面对齐
27
+
28
+ 网关 `ManagedModelPublicResponse` 新增 `thinking_levels: []string`(升序档位 id,按「admin 声明 ∩ wire 层真投递」读时派生)。`listModels` / `listModelsWithStatus` 对 `ManagedModel` 本就原样透传(唯一归一化是 `input_modalities` → `inputModalities`),所以本版**只补类型面与文档**,零运行时改动。
29
+
30
+ ### Added
31
+
32
+ - **`ManagedModel.thinking_levels?: string[]`** —— 该模型可选的思考深度档位 id,取值是 `ThinkingOff` / `ThinkingHigh` / `ThinkingMax`(`'off'` / `'high'` / `'max'`)的子集。字段名保持 wire snake_case,与同结构的 `supported_formats` / `preferred_format` 同风格(见 `src/models/types.ts` 文件头命名约定)。三态语义写进 JSDoc 与 README:`[]` = 该模型没有思考档(不渲染档位选择);`undefined` = 上游未播报(旧网关),调用方必须按"未知"处理,**严禁**回落到自己推档或按模型名 substring 猜。公开方法签名零移除、零改名,旧调用方逐字节兼容。
33
+
34
+ ### 回归闸门
35
+
36
+ - `test/list-models-thinking-levels.test.ts` —— `listModels` / `listModelsWithStatus` 在 `thinking_levels: ['off','high','max']`、单档子集、`[]`、字段缺失四种 payload 下的原样可读性;含"`[]` 与 `undefined` 不可互换"的正向对照(防把空数组当缺失处理的读侧漂移),以及"不因新字段而误伤 `inputModalities` 归一化"的共存用例。
37
+
8
38
  ## [2.17.0] - 2026-08-15 — 桌面 loopback OAuth state 全路径闸 + 端口确定性关闭
9
39
 
10
40
  **回环监听在整个登录期间对本机任意进程开放,state 是唯一的门。** 2.16.0 及更早版本的桌面 loopback `authorize` 不生成也不校验 OAuth `state`(`af2daa0b` 已在源码补上核心校验,但从未发版);且校验只覆盖"带 code"的回调 —— 携带 OAuth error 的回调**绕过 state 直接把登录结算成"用户已拒绝"**,本机恶意进程不猜任何秘密就能打断/塑形一次等待中的登录;重复 `state` 参数取首值即可蒙混(`?code=攻击者的码&state=<正确值>&state=x` 在旧实现下**成功登录到攻击者会话**)。本版把 state 校验提到 `/callback` 所有形态之前,并收紧为"恰好一个"。
package/README.md CHANGED
@@ -7,7 +7,9 @@
7
7
  ## 状态
8
8
 
9
9
  - **主实现 / 事实标准**:本 TS SDK 现为 Acosmi SDK 的主力实现。Go SDK [acosmi-sdk-go](https://github.com/acosmi/acosmi-sdk-go) 已暂停维护,待 TS 稳定后再从 TS 反向翻译补齐。
10
- - **当前版本:`2.15.0`**(sources 四态分类与零结果兼容契约,2026-08-02)。
10
+ - **当前版本:`2.18.0`**(`ManagedModel.thinking_levels` 类型面对齐,2026-08-29)。
11
+ - **`v2.18.0`(加性类型发布)**:`ManagedModel` 新增可选字段 `thinking_levels?: string[]` —— 网关下发的**升序思考档位 id 列表**(`ThinkingOff`/`ThinkingHigh`/`ThinkingMax` 的子集)。`listModels` 对它原样透传,公开签名向后兼容、零行为变化;`[]` = 该模型无思考档,`undefined` = 旧网关未播报(按"未知"处理,严禁自行推档)。详见〈思考档位 `thinking_levels`〉。
12
+ - **`v2.17.0`(安全修复发布)**:桌面 loopback `authorize()` 对 `/callback` 的**一切形态**(成功 / OAuth error / 畸形)先行校验 CSRF `state`,且必须"恰好一个"并严格等值 —— 缺失、重复(含重复的正确值)、错值一律以稳定错误码 `state_mismatch` 拒绝本次登录;此前携带 OAuth error 的回调绕过 state 直接结算 `auth_denied`,本机任意进程零知识即可打断/塑形等待中的登录,且 `?code=…&state=<正确值>&state=x` 这类重复参数可蒙混通过。`finally` 补 `closeIdleConnections()`,每条终止路径以端口完全关闭收尾。公开 API 签名零变化;回归闸门 `test/auth/desktop-loopback-state.test.ts` 十路终止矩阵。
11
13
  - **`v2.15.0`(加性兼容发布)**:新增 `classifySourcesEvent()`、`SourcesEventParseResult` 与稳定 issue code,把 `not_sources`、合法 `empty_sources`、非空 `sources`、`malformed_sources` 明确分开。既有 `parseSourcesEvent()` 的代码路径、宽松判定、`null` 条件和返回对象形状保持原样;现有 consumer 无需改动,新 consumer 才选择严格 API。
12
14
  - **`v2.6.0`(会员订阅查询 + 类型修正,2026-06-04)**:新增 `subscription.getMembership()` / `getSubscriptionTier()` / `subscriptionPrecheck()`;`ManagedModel` 补档位门控字段(`locked`/`freeTier`/`minPlanTier`/`chatRuntimeSupported`/`defaultToolIds`);auth 新增 `ScopeChatBridge`(+read/write/rotate) 与 `chatBridgeScopes()`。**破坏性类型修正**:`BalanceDetail` 形状对齐网关 `InternalBalanceResponse`、`Order` 拆为 `BuyResponse`/`OrderListItem`、`getOrderStatus`/`waitForPayment` 改用 `BuyResponse.paymentStatus`(修死循环)、`PayPayload.payMethod`→`paymentMethod`、`TokenPackage` 对齐 `toProductView`、`WalletStats`/`Transaction` `amount` 由 string 改 number、consume-records 分页修正、notifications WebSocket 用一次性 `stream-ticket` 取代 URL `?token=` JWT。废弃 `listUserSubscriptions`(改用 `getMembership`)、`ModelCoefficient`/`listCoefficients`(系数退役恒空)、`ManagedModel.pricePerMTok`/`isDefault`(公开端点不返回);notifications 设备/偏好方法标 `@experimental`。详见 CHANGELOG。
13
15
  - **`v2.5.1`(格式一致性护栏,2026-05-31)**:`getAdapterForModel` 路由加固 —— `preferred_format` 现仅在**确被 `supported_formats` 收录**时才采信(或 `supported_formats` 未声明时维持原样)。防止上游元数据漂移(如 `preferred_format=anthropic` 但 `supported_formats=[openai]`)把 SDK 路由到模型并不支持的格式端点,撞 `/anthropic`「未绑定 Anthropic」4xx。`supported_formats` 为空/未知(旧上游)时**行为逐字节不变**。新增 3 条 routing 用例钉死矛盾场景。
@@ -176,6 +178,21 @@ console.log(res.videoUrl); // VideoTaskResponse: taskId / status / videoUrl / er
176
178
 
177
179
  > 字段是网关**通用契约**;某厂商支持哪些取值由上游模型决定(如万相尺寸 `宽*高` 星号格式由网关代转)。网关适配范围:OpenAI 兼容图片 + 火山引擎(即梦/豆包)视频 + DashScope 通义万相(wanx)原生异步任务(图片+视频)。
178
180
 
181
+ ## 思考档位 `thinking_levels`(v2.18+)
182
+
183
+ `ManagedModel.thinking_levels?: string[]` —— 该模型**可选的思考深度档位 id**,升序下发,取值是 `ThinkingOff` / `ThinkingHigh` / `ThinkingMax`(`'off'` / `'high'` / `'max'`)的子集。网关按「admin 声明 ∩ wire 层真投递」读时派生;`listModels` 对它**原样透传**(与 `supported_formats` / `preferred_format` 同为 wire snake_case,不做 camelCase 重映射)。
184
+
185
+ **三态必须分开处理 —— `[]` 与 `undefined` 不是同一件事**:
186
+
187
+ ```ts
188
+ const m = (await client.listModels()).find((x) => x.id === modelId)!;
189
+ if (m.thinking_levels === undefined) renderThinkingUnknown(); // 旧网关未播报 → 按"未知"处理
190
+ else if (m.thinking_levels.length === 0) hideThinkingPicker(); // 该模型没有思考档 → 不渲染档位选择
191
+ else renderThinkingPicker(m.thinking_levels); // 升序档位, 原样渲染
192
+ ```
193
+
194
+ 缺失时**严禁**自己推档或按模型名 substring 猜 —— 档位值域归网关模型目录所有,靠运营动作扩张,不靠发 SDK 新版(同 `inputModalities` 开放值域的教训,见 v2.14.0)。该字段与 `capabilities.supports_thinking` / `supports_max_effort` 是**正交**两件事:后者描述模型有无该能力,前者描述**这条链路上此刻真能选哪几档**。
195
+
179
196
  ## 向量 / 重排序(托管模型网关,v2.9+)
180
197
 
181
198
  向量(embedding)与重排序(rerank)走与 chat 同一套**会员计费**(Hold→Settle→Release,按 `total_tokens` 套 input 费率),上游接阿里云百炼 DashScope。仅 `capabilities.supports_embedding` / `supports_rerank` 的托管模型可用;具体上游模型名由管理员在后台自填。
@@ -314,6 +331,32 @@ const stream = client.chatMessagesStream(
314
331
 
315
332
  语义是「链路刚刚有动静」,不是「来了一个事件」;对每条 SSE 行触发一次,早于任何过滤与解析。回调抛出的错误会被吞掉且不中断流(旁路信号不该有能力杀死主链路)。不传时行为逐字节不变。
316
333
 
334
+ ### 网关请求 ID 回调 `onGatewayRequestID`(v2.19+)
335
+
336
+ 如果你要把**用户可见的失败**关联回上游那一次网关调用与它产生的计费行,接这个回调。
337
+
338
+ 网关在响应头 `X-Acosmi-Request-Id`(常量 `GATEWAY_REQUEST_ID_HEADER`)里下发 `consumeRequestID` —— 它就是 `managed_model_usage_logs.request_id` 的值,是能 join 到计费行的那个键。
339
+
340
+ > ⚠️ 它**不是**网关的传输层 `X-Request-ID`。那一个独立生成、从不写进任何计费表,两者永不相等。用错的后果是恒空 join —— 不报错,只是下次事故照样查不动。
341
+
342
+ ```ts
343
+ let gatewayRequestId: string | undefined;
344
+
345
+ const stream = client.chatMessagesStream(
346
+ modelId,
347
+ { messages, max_tokens: 4096 },
348
+ abortSignal,
349
+ onUpstreamActivity,
350
+ id => { gatewayRequestId = id; }, // ← 响应头到达时触发,早于第一个事件
351
+ );
352
+ ```
353
+
354
+ 回调在响应头到达后触发**至多一次**,且在第一个 SSE 事件之前 —— 因此它覆盖「流中段被掐断」「上游 200 但零事件」「HTTP 错误」全部形态;流内事件在「事件根本没来」的场景里恰恰不存在,而那正是最需要诊断的那一种。
355
+
356
+ 同步路径 `chatMessages` / `chat` 的第 4 个实参是同一个回调。
357
+
358
+ 网关没下发(旧版本 / 非托管路径)时回调**一次都不触发**,SDK 绝不合成占位值;流照常出。浏览器端消费方还需网关 CORS `Access-Control-Expose-Headers` 放行该头(网关 v2026-09-01 起已放行)。
359
+
317
360
  ### Sources SSE 四态分类(v2.15+)
318
361
 
319
362
  `sources: []` 是检索成功但没有可展示引用的合法零结果,不是传输损坏。需要精确区分状态的新 consumer 使用加性接口 `classifySourcesEvent()`:
@@ -602,6 +645,8 @@ const tokens = newTokenSet(tokenResp, reg.client_id, process.env.ACOSMI_SERVER_U
602
645
  await new FileTokenStore('./tokens.json').save(tokens);
603
646
  ```
604
647
 
648
+ > **state 语义(v2.17.0 起)**:桌面 loopback 流程自动生成 32 字节随机 `state` 并对 `/callback` 的一切形态先行校验 —— 恰好一个且严格等值,缺失 / 重复 / 错值一律以错误码 `state_mismatch` 拒绝本次登录并关闭 listener(含携带 OAuth error 的回调;用户真拒绝须回传正确 state 才结算为 `auth_denied`)。调用方零改动:`state` 由 SDK 内部管理,不出现在 `authorize()` 的公开签名里。授权服务器按 RFC 6749 §4.1.2.1 在**错误响应**上也必须原样回传 `state`(Acosmi 官方 consent 页已适配)。
649
+ >
605
650
  > 浏览器侧(无法启 loopback HTTP server)请改用 v1.4.0+ Web OAuth 原语 `discoverWebOAuthMetadata` + `registerWebOAuthClient` + `createWebAuthorizationRequest` + `completeWebAuthorizationRequest`,由调用方实现 popup / 同窗口 redirect handler,SDK 负责 PKCE / state 校验 / token 兑换。
606
651
 
607
652
  ### Token 持久化
@@ -1124,7 +1169,10 @@ npm run docs # 经 TypeDoc 生成 API 参考到 docs/api/
1124
1169
 
1125
1170
  | 版本 | 状态 | 概要 |
1126
1171
  | --- | --- | --- |
1127
- | 2.16.0 | **当前版本** | **chat 超时预算真正下传 + 流式活性回调(2026-08-06)**。`chat` / `chatMessagesAnthropic` / `chatMessagesOpenAI` / `generateVideo` 此前漏传 `doJSONFullRaw` 的第 5 实参,内层 **30 秒**默认值恒先于外层 11 分钟预算触发 —— v1.6.0 那次"调整为 11min"一天都没生效过(生产实证:单日 29 条 latency≈30 000 ms 的 499,横跨 4 厂商 5 模型,受害最重的是默认主循环模型)。加性导出 `CHAT_REQUEST_TIMEOUT_MS`;`chatStream` / `chatMessagesStream` 新增第 4 个可选实参 `onUpstreamActivity`,让被 `isSSECommentLine` 吞掉的保活注释行(以及 OpenAI 格式下零事件的 data 行)能抵达消费方的空闲看门狗。不传回调时行为逐字节不变。 |
1172
+ | 2.19.0 | **当前版本** | **网关消费请求 ID 透出(2026-09-01)**。网关把 `consumeRequestID`(即 `managed_model_usage_logs.request_id`)放进 `X-Acosmi-Request-Id` 响应头;加性导出 `GATEWAY_REQUEST_ID_HEADER` `GatewayRequestIDCallback`,`chatMessagesStream` / `chatStream` 新增第 5 个可选实参、`chatMessages` / `chat` 新增第 4 个可选实参。响应头在首字节之前到达,因此覆盖流中段中断 / 零事件 / HTTP 错误全部形态。旧网关下回调零触发、绝不合成占位值,流照常出。不传回调时行为逐字节不变。 |
1173
+ | 2.18.0 | 稳定版 | **`ManagedModel.thinking_levels` 类型面对齐(2026-08-29)**。加性新增可选字段 `thinking_levels?: string[]`:网关下发的升序思考档位 id 列表(`'off'`/`'high'`/`'max'` 的子集,按「admin 声明 ∩ wire 层真投递」派生)。`listModels` 原样透传,无归一化、无新方法、公开签名零变化。`[]` = 该模型无思考档;`undefined` = 旧网关未播报,调用方按"未知"处理,严禁按模型名推档。 |
1174
+ | 2.17.0 | 稳定版 | **桌面 loopback OAuth state 全路径闸 + 端口确定性关闭(2026-08-15)**。`/callback` 一切形态(成功 / OAuth error / 畸形)先验 `state` 且必须恰好一个并严格等值;缺失 / 重复(含重复的正确值)/ 错值一律 `state_mismatch` 拒绝且不再被误结算为 `auth_denied`;错误信息只描述形态,不回显 code / state / token / 完整 callback query。`finally` 补 `closeIdleConnections()`(Node 18 上 `close()` 不关残留 idle keep-alive)。用户真拒绝(OAuth error + 正确 state)语义保留为 `auth_denied`。公开 API 签名零变化。 |
1175
+ | 2.16.0 | 稳定版 | **chat 超时预算真正下传 + 流式活性回调(2026-08-06)**。`chat` / `chatMessagesAnthropic` / `chatMessagesOpenAI` / `generateVideo` 此前漏传 `doJSONFullRaw` 的第 5 实参,内层 **30 秒**默认值恒先于外层 11 分钟预算触发 —— v1.6.0 那次"调整为 11min"一天都没生效过(生产实证:单日 29 条 latency≈30 000 ms 的 499,横跨 4 厂商 5 模型,受害最重的是默认主循环模型)。加性导出 `CHAT_REQUEST_TIMEOUT_MS`;`chatStream` / `chatMessagesStream` 新增第 4 个可选实参 `onUpstreamActivity`,让被 `isSSECommentLine` 吞掉的保活注释行(以及 OpenAI 格式下零事件的 data 行)能抵达消费方的空闲看门狗。不传回调时行为逐字节不变。 |
1128
1176
  | 2.15.0 | 稳定版 | **sources 四态分类与零结果契约(2026-08-02)**。加性新增 `classifySourcesEvent`、`SourcesEventParseResult` 与稳定 issue code,区分非 sources、合法空结果、有效结果和结构损坏;未知额外字段继续兼容。既有 `parseSourcesEvent` 的返回形状、宽松解析和 `null` 条件保持不变。 |
1129
1177
  | 2.14.0 | 稳定版 | **托管模型 input modalities 开放值域(2026-08-02)**。snake_case/camelCase 归一规则对称,数据字段允许未来新增标签;查询 API 仍保留已知标签自动补全。现网 camelCase 路径行为不变。 |
1130
1178
  | 2.13.0 | 稳定版 | **邀请奖励窗口重置券(2026-08-01)**。加性新增窗口重置券总览与幂等核销 API,不改变既有 token、额度和会员调用。 |
@@ -2317,6 +2317,22 @@ function notifyUpstreamActivity(cb) {
2317
2317
  } catch {
2318
2318
  }
2319
2319
  }
2320
+ var GATEWAY_REQUEST_ID_HEADER = "X-Acosmi-Request-Id";
2321
+ function readGatewayRequestID(headers) {
2322
+ const raw = headers.get(GATEWAY_REQUEST_ID_HEADER);
2323
+ if (!raw) return void 0;
2324
+ const trimmed = raw.trim();
2325
+ return trimmed === "" ? void 0 : trimmed;
2326
+ }
2327
+ function notifyGatewayRequestID(cb, headers) {
2328
+ if (!cb) return;
2329
+ const id = readGatewayRequestID(headers);
2330
+ if (id === void 0) return;
2331
+ try {
2332
+ cb(id);
2333
+ } catch {
2334
+ }
2335
+ }
2320
2336
  var DEFAULT_API_TIMEOUT_MS = 6e4;
2321
2337
  function newDeferred() {
2322
2338
  let resolve;
@@ -3024,7 +3040,7 @@ var Client = class _Client {
3024
3040
  * 响应的 tokenRemaining / callRemaining 字段来自服务端 Header, 反映结算后余额
3025
3041
  * v0.5.0: 根据 provider 自动路由到 /anthropic 或 /chat 端点
3026
3042
  */
3027
- async chat(modelID, req, signal) {
3043
+ async chat(modelID, req, signal, onGatewayRequestID) {
3028
3044
  const r = { ...req, stream: false };
3029
3045
  const ctl = withRequestTimeout(CHAT_REQUEST_TIMEOUT_MS, signal);
3030
3046
  try {
@@ -3037,6 +3053,7 @@ var Client = class _Client {
3037
3053
  ctl.signal,
3038
3054
  CHAT_REQUEST_TIMEOUT_MS
3039
3055
  );
3056
+ notifyGatewayRequestID(onGatewayRequestID, headers);
3040
3057
  const resp = adapter.parseResponse(result);
3041
3058
  const v1 = headers.get("X-Token-Remaining");
3042
3059
  if (v1) {
@@ -3157,28 +3174,29 @@ var Client = class _Client {
3157
3174
  * Anthropic → chatMessagesAnthropic (现有路径, POST /anthropic)
3158
3175
  * 其他厂商 → chatMessagesOpenAI (POST /chat, 响应转换为 AnthropicResponse)
3159
3176
  */
3160
- async chatMessages(modelID, req, signal) {
3177
+ async chatMessages(modelID, req, signal, onGatewayRequestID) {
3161
3178
  const m = await this.ensureModelCached(modelID, signal);
3162
3179
  const adapter = getAdapterForModel(m);
3163
3180
  if (adapter.format() === 0 /* Anthropic */) {
3164
- return this.chatMessagesAnthropic(modelID, req, adapter, signal);
3181
+ return this.chatMessagesAnthropic(modelID, req, adapter, signal, onGatewayRequestID);
3165
3182
  }
3166
- return this.chatMessagesOpenAI(modelID, req, adapter, signal);
3183
+ return this.chatMessagesOpenAI(modelID, req, adapter, signal, onGatewayRequestID);
3167
3184
  }
3168
- async chatMessagesAnthropic(modelID, req, adapter, signal) {
3185
+ async chatMessagesAnthropic(modelID, req, adapter, signal, onGatewayRequestID) {
3169
3186
  const r = { ...req, stream: false };
3170
3187
  const ctl = withRequestTimeout(CHAT_REQUEST_TIMEOUT_MS, signal);
3171
3188
  try {
3172
3189
  const caps = this.getCachedCapabilities(modelID) ?? zeroModelCapabilities();
3173
3190
  const body = adapter.buildRequestBody(caps, r);
3174
3191
  const data = JSON.stringify(body);
3175
- const { result } = await this.doJSONFullRaw(
3192
+ const { result, headers } = await this.doJSONFullRaw(
3176
3193
  "POST",
3177
3194
  `/managed-models/${encodeURIComponent(modelID)}/anthropic`,
3178
3195
  data,
3179
3196
  ctl.signal,
3180
3197
  CHAT_REQUEST_TIMEOUT_MS
3181
3198
  );
3199
+ notifyGatewayRequestID(onGatewayRequestID, headers);
3182
3200
  const rawStr = new TextDecoder().decode(result);
3183
3201
  try {
3184
3202
  const wrapper = JSON.parse(rawStr);
@@ -3203,7 +3221,7 @@ var Client = class _Client {
3203
3221
  ctl.dispose();
3204
3222
  }
3205
3223
  }
3206
- async chatMessagesOpenAI(modelID, req, adapter, signal) {
3224
+ async chatMessagesOpenAI(modelID, req, adapter, signal, onGatewayRequestID) {
3207
3225
  const r = { ...req, stream: false };
3208
3226
  const ctl = withRequestTimeout(CHAT_REQUEST_TIMEOUT_MS, signal);
3209
3227
  try {
@@ -3211,13 +3229,14 @@ var Client = class _Client {
3211
3229
  const body = adapter.buildRequestBody(caps, r);
3212
3230
  const data = JSON.stringify(body);
3213
3231
  const endpoint = `/managed-models/${encodeURIComponent(modelID)}${adapter.endpointSuffix()}`;
3214
- const { result } = await this.doJSONFullRaw(
3232
+ const { result, headers } = await this.doJSONFullRaw(
3215
3233
  "POST",
3216
3234
  endpoint,
3217
3235
  data,
3218
3236
  ctl.signal,
3219
3237
  CHAT_REQUEST_TIMEOUT_MS
3220
3238
  );
3239
+ notifyGatewayRequestID(onGatewayRequestID, headers);
3221
3240
  const { parseOpenAIResponseToAnthropic: parseOpenAIResponseToAnthropic2 } = await Promise.resolve().then(() => (init_openai(), openai_exports));
3222
3241
  return parseOpenAIResponseToAnthropic2(result);
3223
3242
  } finally {
@@ -3229,10 +3248,11 @@ var Client = class _Client {
3229
3248
  * v0.5.0: 根据 adapter 路由端点
3230
3249
  *
3231
3250
  * @param onUpstreamActivity 见 {@link UpstreamActivityCallback}
3251
+ * @param onGatewayRequestID 见 {@link GatewayRequestIDCallback}
3232
3252
  */
3233
- chatStream(modelID, req, signal, onUpstreamActivity) {
3253
+ chatStream(modelID, req, signal, onUpstreamActivity, onGatewayRequestID) {
3234
3254
  return {
3235
- [Symbol.asyncIterator]: () => this.chatStreamGen(modelID, req, signal, false, onUpstreamActivity)
3255
+ [Symbol.asyncIterator]: () => this.chatStreamGen(modelID, req, signal, false, onUpstreamActivity, onGatewayRequestID)
3236
3256
  };
3237
3257
  }
3238
3258
  /**
@@ -3241,13 +3261,14 @@ var Client = class _Client {
3241
3261
  * 无 started/settled/failed 自定义事件, 无 data: [DONE], message_stop 为自然结束
3242
3262
  *
3243
3263
  * @param onUpstreamActivity 见 {@link UpstreamActivityCallback}
3264
+ * @param onGatewayRequestID 见 {@link GatewayRequestIDCallback}
3244
3265
  */
3245
- chatMessagesStream(modelID, req, signal, onUpstreamActivity) {
3266
+ chatMessagesStream(modelID, req, signal, onUpstreamActivity, onGatewayRequestID) {
3246
3267
  return {
3247
- [Symbol.asyncIterator]: () => this.chatMessagesStreamGen(modelID, req, signal, false, onUpstreamActivity)
3268
+ [Symbol.asyncIterator]: () => this.chatMessagesStreamGen(modelID, req, signal, false, onUpstreamActivity, onGatewayRequestID)
3248
3269
  };
3249
3270
  }
3250
- async *chatStreamGen(modelID, req, signal, retried, onUpstreamActivity) {
3271
+ async *chatStreamGen(modelID, req, signal, retried, onUpstreamActivity, onGatewayRequestID) {
3251
3272
  const r = { ...req, stream: true };
3252
3273
  const { body, adapter } = await this.buildChatRequest(modelID, r, signal);
3253
3274
  const token = await this.ensureToken(signal);
@@ -3280,9 +3301,10 @@ var Client = class _Client {
3280
3301
  `stream: unauthorized and refresh failed: ${refreshErr instanceof Error ? refreshErr.message : String(refreshErr)}`
3281
3302
  );
3282
3303
  }
3283
- yield* this.chatStreamGen(modelID, req, signal, true, onUpstreamActivity);
3304
+ yield* this.chatStreamGen(modelID, req, signal, true, onUpstreamActivity, onGatewayRequestID);
3284
3305
  return;
3285
3306
  }
3307
+ notifyGatewayRequestID(onGatewayRequestID, resp.headers);
3286
3308
  if (!resp.ok) {
3287
3309
  const bodyBytes = await readLimited(resp.body, maxErrorBodySize);
3288
3310
  throw parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers);
@@ -3317,7 +3339,7 @@ var Client = class _Client {
3317
3339
  }
3318
3340
  }
3319
3341
  }
3320
- async *chatMessagesStreamGen(modelID, req, signal, retried, onUpstreamActivity) {
3342
+ async *chatMessagesStreamGen(modelID, req, signal, retried, onUpstreamActivity, onGatewayRequestID) {
3321
3343
  const r = { ...req, stream: true };
3322
3344
  const { body, adapter } = await this.buildChatRequest(modelID, r, signal);
3323
3345
  const token = await this.ensureToken(signal);
@@ -3350,9 +3372,10 @@ var Client = class _Client {
3350
3372
  `messages stream: unauthorized and refresh failed: ${refreshErr instanceof Error ? refreshErr.message : String(refreshErr)}`
3351
3373
  );
3352
3374
  }
3353
- yield* this.chatMessagesStreamGen(modelID, req, signal, true, onUpstreamActivity);
3375
+ yield* this.chatMessagesStreamGen(modelID, req, signal, true, onUpstreamActivity, onGatewayRequestID);
3354
3376
  return;
3355
3377
  }
3378
+ notifyGatewayRequestID(onGatewayRequestID, resp.headers);
3356
3379
  if (!resp.ok) {
3357
3380
  const bodyBytes = await readLimited(resp.body, maxErrorBodySize);
3358
3381
  throw parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers);
@@ -7812,6 +7835,6 @@ function brandCredential(c) {
7812
7835
  return c;
7813
7836
  }
7814
7837
 
7815
- export { AGENT_RUN_META_TITLE, AGENT_RUN_META_WORKSPACE, ALL_INTEGRATION_STATUS, ALL_PLATFORMS, ALL_REGIONS, AgentRunStreamError, AgentRunsClient, AnthropicAdapter, AudienceEnum, BillingModeEnum, BucketClassCommercial, BucketClassGeneric, BusinessError, CHAT_REQUEST_TIMEOUT_MS, ChatBridgeClient, Client, ComplianceClient, CompliancePollError, CrabCodeByokClient, DEFAULT_API_TIMEOUT_MS, DEFAULT_GATEWAY_BASE_URL, LocalStorageTokenStore as DefaultBrowserTokenStore, DefaultRetryPolicy, ErrAuthDenied, ErrBillingCallbackCannotCommit, ErrBillingCommitRequiresLocalVerify, ErrBillingS2sForbidden, ErrBrowserOpen, ErrComplianceStepUpRequired, ErrDiscovery, ErrEnvelopeGateClosed, ErrOAuthCORSBlocked, ErrProviderNotConfigured, ErrProviderUnknownNoRetry, ErrRefreshProxyFailed, ErrRegistration, ErrSSLProxy, ErrSealApprovalContractHashMismatch, ErrSealApprovalExpired, ErrSealApprovalLocationMismatch, ErrSealApprovalNonceUsed, ErrSealApprovalNotApproved, ErrSealApprovalSealMismatch, ErrSealApprovalTransactorMismatch, ErrSealUseAlreadyConsumed, ErrStateMismatch, ErrTimeout, ErrTokenExchange, ErrTokenExpired, EventAuthURL, EventComplete, EventError, FileTokenStore, FilterStatusAdminBypass, FilterStatusDisabledByFlag, FilterStatusFallbackMissingUser, FilterStatusFallbackNoBuckets, FilterStatusFallbackTkdistError, FilterStatusFallbackTkdistSkew, FilterStatusInternalBypass, FilterStatusOK, FilterStatusUnknown, HTTPError, IdempotencyKeyHeader, InMemoryTokenStore, LocalStorageTokenStore, ModelNotFoundError, NetworkError, OAuthTokenEndpointError, OpenAIAdapter, OrderTerminalError, ProductFamilyEnum, ProviderFormat, RETRY_ADVICE_REASONS, RateLimitError, RegionScopeEnum, ScopeAI, ScopeAccount, ScopeAgentAccessManage, ScopeChatBridge, ScopeChatBridgeRead, ScopeChatBridgeRotate, ScopeChatBridgeWrite, ScopeComplianceContractSigningRead, ScopeComplianceContractSigningWrite, ScopeComplianceContractTemplateRead, ScopeComplianceContractTemplateWrite, ScopeComplianceEvidenceRead, ScopeComplianceEvidenceWrite, ScopeComplianceReportsPublish, ScopeComplianceReportsRead, ScopeComplianceReportsWrite, ScopeComplianceSealApprovalApprove, ScopeComplianceSealApprovalRequest, ScopeComplianceSealManage, ScopeComplianceSealUseExecute, ScopeComplianceTimestampIssue, ScopeComplianceTimestampVerify, ScopeEntitlements, ScopeModels, ScopeModelsChat, ScopeProfile, ScopeRemoteControl, ScopeRemoteControlAgentRun, ScopeRemoteControlPermissionResponse, ScopeRemoteControlSessionControl, ScopeSkillStore, ScopeSkills, ScopeTokenPackages, ScopeTools, ScopeToolsExecute, ScopeWallet, ScopeWalletReadonly, ServerToolTypeWebSearch, StreamError, ThinkingHigh, ThinkingHighMinMaxTokens, ThinkingMax, ThinkingMaxFallbackMaxTokens, ThinkingOff, agentAccessScopes, allScopes, anthropicResponseTextContent, anthropicResponseThinkingContent, anthropicResponseToolUseBlocks, apiResponseBusinessError, apiResponseGetMessage, asCredentialRef, authorize, bucketInfoIsCommercial, bucketRowIsCommercial, buildBetas, chatBridgeScopes, classifyComplianceError, classifySourcesEvent, commerceScopes, completeWebAuthorizationRequest, complianceErrorToRetryAdvice, complianceScopes, computeBackoff, createWebAuthorizationRequest, defaultRetryable, defaultSafeToRetry, discover, discoverWebOAuthMetadata, discoverWithProfile, effectivePolicy, exchangeCode, extractAnthropicBlockMeta, fileLockDefaults, findDesktopVisualUnderstandingModel, findFirstModelByInputModality, generateState, getAdapter, getAdapterForModel, getWindowLimitStreamDetails, isBillingConfirmable, isChannelInboundEvent, isComplianceBusinessError, isComplianceTerminalError, isContinuableWindowLimitError, isIntegrationStatus, isInvalidGrantError, isPlatform, isRegion, isSSECommentLine, isSSLError, isTerminalRemoteEvent, isValidTokenSet, isWindowLimitError, isWindowLimitStreamError, maxEndUserIdLength, modelScopes, modelSupportsImageInput, modelSupportsInputModality, newFileTokenStore, newThinkingConfig, newTokenSet, newWebSearchTool, normalizeGatewayBaseURL, normalizeOverrideBaseURL, parseNotificationEvent, parseRemoteControlEvent, parseSettlement, parseSourcesEvent, refreshToken, register, registerWebOAuthClient, remoteControlScopes, retryReasonForComplianceKey, retryReasonForOAuthError, revokeToken, sanitize_exports as sanitize, skillScopes, tokenSetIsExpired, uniqueMerge, validateEndUserId };
7838
+ export { AGENT_RUN_META_TITLE, AGENT_RUN_META_WORKSPACE, ALL_INTEGRATION_STATUS, ALL_PLATFORMS, ALL_REGIONS, AgentRunStreamError, AgentRunsClient, AnthropicAdapter, AudienceEnum, BillingModeEnum, BucketClassCommercial, BucketClassGeneric, BusinessError, CHAT_REQUEST_TIMEOUT_MS, ChatBridgeClient, Client, ComplianceClient, CompliancePollError, CrabCodeByokClient, DEFAULT_API_TIMEOUT_MS, DEFAULT_GATEWAY_BASE_URL, LocalStorageTokenStore as DefaultBrowserTokenStore, DefaultRetryPolicy, ErrAuthDenied, ErrBillingCallbackCannotCommit, ErrBillingCommitRequiresLocalVerify, ErrBillingS2sForbidden, ErrBrowserOpen, ErrComplianceStepUpRequired, ErrDiscovery, ErrEnvelopeGateClosed, ErrOAuthCORSBlocked, ErrProviderNotConfigured, ErrProviderUnknownNoRetry, ErrRefreshProxyFailed, ErrRegistration, ErrSSLProxy, ErrSealApprovalContractHashMismatch, ErrSealApprovalExpired, ErrSealApprovalLocationMismatch, ErrSealApprovalNonceUsed, ErrSealApprovalNotApproved, ErrSealApprovalSealMismatch, ErrSealApprovalTransactorMismatch, ErrSealUseAlreadyConsumed, ErrStateMismatch, ErrTimeout, ErrTokenExchange, ErrTokenExpired, EventAuthURL, EventComplete, EventError, FileTokenStore, FilterStatusAdminBypass, FilterStatusDisabledByFlag, FilterStatusFallbackMissingUser, FilterStatusFallbackNoBuckets, FilterStatusFallbackTkdistError, FilterStatusFallbackTkdistSkew, FilterStatusInternalBypass, FilterStatusOK, FilterStatusUnknown, GATEWAY_REQUEST_ID_HEADER, HTTPError, IdempotencyKeyHeader, InMemoryTokenStore, LocalStorageTokenStore, ModelNotFoundError, NetworkError, OAuthTokenEndpointError, OpenAIAdapter, OrderTerminalError, ProductFamilyEnum, ProviderFormat, RETRY_ADVICE_REASONS, RateLimitError, RegionScopeEnum, ScopeAI, ScopeAccount, ScopeAgentAccessManage, ScopeChatBridge, ScopeChatBridgeRead, ScopeChatBridgeRotate, ScopeChatBridgeWrite, ScopeComplianceContractSigningRead, ScopeComplianceContractSigningWrite, ScopeComplianceContractTemplateRead, ScopeComplianceContractTemplateWrite, ScopeComplianceEvidenceRead, ScopeComplianceEvidenceWrite, ScopeComplianceReportsPublish, ScopeComplianceReportsRead, ScopeComplianceReportsWrite, ScopeComplianceSealApprovalApprove, ScopeComplianceSealApprovalRequest, ScopeComplianceSealManage, ScopeComplianceSealUseExecute, ScopeComplianceTimestampIssue, ScopeComplianceTimestampVerify, ScopeEntitlements, ScopeModels, ScopeModelsChat, ScopeProfile, ScopeRemoteControl, ScopeRemoteControlAgentRun, ScopeRemoteControlPermissionResponse, ScopeRemoteControlSessionControl, ScopeSkillStore, ScopeSkills, ScopeTokenPackages, ScopeTools, ScopeToolsExecute, ScopeWallet, ScopeWalletReadonly, ServerToolTypeWebSearch, StreamError, ThinkingHigh, ThinkingHighMinMaxTokens, ThinkingMax, ThinkingMaxFallbackMaxTokens, ThinkingOff, agentAccessScopes, allScopes, anthropicResponseTextContent, anthropicResponseThinkingContent, anthropicResponseToolUseBlocks, apiResponseBusinessError, apiResponseGetMessage, asCredentialRef, authorize, bucketInfoIsCommercial, bucketRowIsCommercial, buildBetas, chatBridgeScopes, classifyComplianceError, classifySourcesEvent, commerceScopes, completeWebAuthorizationRequest, complianceErrorToRetryAdvice, complianceScopes, computeBackoff, createWebAuthorizationRequest, defaultRetryable, defaultSafeToRetry, discover, discoverWebOAuthMetadata, discoverWithProfile, effectivePolicy, exchangeCode, extractAnthropicBlockMeta, fileLockDefaults, findDesktopVisualUnderstandingModel, findFirstModelByInputModality, generateState, getAdapter, getAdapterForModel, getWindowLimitStreamDetails, isBillingConfirmable, isChannelInboundEvent, isComplianceBusinessError, isComplianceTerminalError, isContinuableWindowLimitError, isIntegrationStatus, isInvalidGrantError, isPlatform, isRegion, isSSECommentLine, isSSLError, isTerminalRemoteEvent, isValidTokenSet, isWindowLimitError, isWindowLimitStreamError, maxEndUserIdLength, modelScopes, modelSupportsImageInput, modelSupportsInputModality, newFileTokenStore, newThinkingConfig, newTokenSet, newWebSearchTool, normalizeGatewayBaseURL, normalizeOverrideBaseURL, parseNotificationEvent, parseRemoteControlEvent, parseSettlement, parseSourcesEvent, refreshToken, register, registerWebOAuthClient, remoteControlScopes, retryReasonForComplianceKey, retryReasonForOAuthError, revokeToken, sanitize_exports as sanitize, skillScopes, tokenSetIsExpired, uniqueMerge, validateEndUserId };
7816
7839
  //# sourceMappingURL=index.mjs.map
7817
7840
  //# sourceMappingURL=index.mjs.map