@acosmi/sdk-ts 2.15.0 → 2.16.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,27 @@ 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.16.0] - 2026-08-06 — chat 超时预算真正下传 + 流式活性回调
9
+
10
+ **一个预算只有在被传下去时才存在。** `chat` / `chatMessagesAnthropic` / `chatMessagesOpenAI` 三条推理链路都用 `withRequestTimeout(CHAT_REQUEST_TIMEOUT_MS)` 建了 11 分钟的外层预算,却只把 `ctl.signal` 传给 `doJSONFullRaw` —— 后者的 `timeoutMs` 形参有 **30 秒**默认值,会**另建**一个计时器并恒先于外层触发。于是 v1.6.0 那次"调整为 11min 以容纳 DeepSeek 保活窗口"的改动,**一天都没生效过**,而它上方的注释还在声称它已生效。
11
+
12
+ 这不是理论缺陷。生产网关单日 **29 条** latency 落在 27 831–30 046 ms 的 499(客户端主动断开),横跨 **4 个厂商 5 个模型**;受害最重的恰是各客户端的默认主循环模型 —— 也正是唯一拿到网关 11 分钟长首字节预算的那个 provider。它拿着最宽的服务端预算,死得最惨,因为杀它的计时器在客户端。真实用户主动取消的 latency 是随机的(1 294 / 1 575 ms),与这一串高度聚集的 30 秒在同一张表里一眼可分。
13
+
14
+ ### Fixed
15
+
16
+ - **`chat` / `chatMessagesAnthropic` / `chatMessagesOpenAI` / `generateVideo` 显式下传 `CHAT_REQUEST_TIMEOUT_MS`** —— 与同文件 `embeddings` / `rerank` / `generateImage` 三个一直正确的兄弟调用对齐。`generateVideo` 此前连外层预算都没有,同样被钉在 30 秒;现按其直接兄弟 `generateImage` 的形状修复(单次网络操作,不另加外层 controller)。
17
+ - **`Client.chat` 上方那条 v1.6.0 注释重写** —— 它描述的是一个从未交付的行为。注释与实测冲突时以实测为准,且必须同 PR 修掉;留着它就是给下一个读代码的人埋雷。
18
+
19
+ ### Added
20
+
21
+ - **`CHAT_REQUEST_TIMEOUT_MS` 导出** —— 供回归闸门按**符号**断言,避免测试抄字面量后与真源各自漂移(抄件断言恒绿 = 零覆盖)。消费方要更短的预算传 `signal` 即可,`withRequestTimeout` 取二者先到者。
22
+ - **`UpstreamActivityCallback` + `chatStream` / `chatMessagesStream` 的第 4 个可选实参 `onUpstreamActivity`** —— 消费方的流空闲看门狗判据是"多久没收到事件",但 SSE 上有两类**有字节、无事件**的情形对它完全失明:① 上游/网关推理前发的保活注释行被 `isSSECommentLine` 吞掉;② OpenAI 格式下 converter 对某些 data 行返回零事件。**心跳只有在抵达做判决的那一层时才叫心跳** —— 网关补心跳而 SDK 吞掉,等于没补。本回调对每一条 SSE 行触发一次(含注释行),早于任何过滤与解析;回调抛错被吞掉且不中断流(旁路信号不该有能力杀死主链路)。不传时行为逐字节不变。
23
+
24
+ ### 回归闸门
25
+
26
+ - `test/chat-timeout-budget.test.ts` —— 四条链路的**行为**断言(活过 30 秒、死在 `CHAT_REQUEST_TIMEOUT_MS`),外加一条 **default-deny 结构闸门**:`doJSONFullRaw` 的每个调用点必须显式传预算,控制面端点要豁免须进具名 allowlist 并写明理由。附负向对照,防扫描器坏掉后闸门恒绿。
27
+ - `test/stream-upstream-activity.test.ts` —— 判据是"第一个事件到达前已有 ≥3 次活性",只可能由 3 条保活注释行产生;刻意不用"活性次数 > 事件数",那条在注释行根本没进循环时会假绿。
28
+
8
29
  ## [2.15.0] - 2026-08-02 — sources 四态分类与零结果契约
9
30
 
10
31
  ### Added
package/README.md CHANGED
@@ -290,6 +290,30 @@ for await (const ev of stream) {
290
290
 
291
291
  `chatStreamWithUsage()` 返回带 usage/error/sources 标签的 AsyncIterable,便于聚合统计(详见 `src/core/client.ts`)。
292
292
 
293
+ ### 上游活性回调 `onUpstreamActivity`(v2.16+)
294
+
295
+ 如果你的集成层自带**流空闲看门狗**("多久没收到事件就判定连接死了"),必须接这个回调,否则看门狗会误杀健康连接。
296
+
297
+ SSE 上有两类**有字节、无事件**的情形,看门狗对它们完全失明:
298
+
299
+ 1. 上游(如 DeepSeek)与网关在开始推理前发的保活注释行 `: keep-alive` —— 按 SSE 规范它们不构成事件,被 `isSSECommentLine` 跳过;
300
+ 2. OpenAI 格式下 converter 对某些 data 行返回零事件。
301
+
302
+ 两种情形连接都健康、字节都在流动。**心跳只有在抵达做判决的那一层时才叫心跳** —— 网关补了心跳而 SDK 吞掉,等于没补。
303
+
304
+ ```ts
305
+ let lastActivity = Date.now();
306
+
307
+ const stream = client.chatMessagesStream(
308
+ modelId,
309
+ { messages, max_tokens: 4096 },
310
+ abortSignal,
311
+ () => { lastActivity = Date.now(); }, // ← 每条 SSE 行触发一次,含注释行
312
+ );
313
+ ```
314
+
315
+ 语义是「链路刚刚有动静」,不是「来了一个事件」;对每条 SSE 行触发一次,早于任何过滤与解析。回调抛出的错误会被吞掉且不中断流(旁路信号不该有能力杀死主链路)。不传时行为逐字节不变。
316
+
293
317
  ### Sources SSE 四态分类(v2.15+)
294
318
 
295
319
  `sources: []` 是检索成功但没有可展示引用的合法零结果,不是传输损坏。需要精确区分状态的新 consumer 使用加性接口 `classifySourcesEvent()`:
@@ -1100,7 +1124,8 @@ npm run docs # 经 TypeDoc 生成 API 参考到 docs/api/
1100
1124
 
1101
1125
  | 版本 | 状态 | 概要 |
1102
1126
  | --- | --- | --- |
1103
- | 2.15.0 | **当前版本** | **sources 四态分类与零结果契约(2026-08-02)**。加性新增 `classifySourcesEvent`、`SourcesEventParseResult` 与稳定 issue code,区分非 sources、合法空结果、有效结果和结构损坏;未知额外字段继续兼容。既有 `parseSourcesEvent` 的返回形状、宽松解析和 `null` 条件保持不变。 |
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 行)能抵达消费方的空闲看门狗。不传回调时行为逐字节不变。 |
1128
+ | 2.15.0 | 稳定版 | **sources 四态分类与零结果契约(2026-08-02)**。加性新增 `classifySourcesEvent`、`SourcesEventParseResult` 与稳定 issue code,区分非 sources、合法空结果、有效结果和结构损坏;未知额外字段继续兼容。既有 `parseSourcesEvent` 的返回形状、宽松解析和 `null` 条件保持不变。 |
1104
1129
  | 2.14.0 | 稳定版 | **托管模型 input modalities 开放值域(2026-08-02)**。snake_case/camelCase 归一规则对称,数据字段允许未来新增标签;查询 API 仍保留已知标签自动补全。现网 camelCase 路径行为不变。 |
1105
1130
  | 2.13.0 | 稳定版 | **邀请奖励窗口重置券(2026-08-01)**。加性新增窗口重置券总览与幂等核销 API,不改变既有 token、额度和会员调用。 |
1106
1131
  | 2.12.0 | 稳定版 | **5 小时窗口软限额(2026-07-11)**。加性透传 `windowOverridable`、继续开关与结构化状态;老网关缺字段时按硬等待处理。 |
@@ -1123,7 +1148,7 @@ npm run docs # 经 TypeDoc 生成 API 参考到 docs/api/
1123
1148
  | 1.8.1 | 稳定版 | **enterprise 企业席位域落地(商品化总规划 P6a)**。新增 `client.enterprise.*`:`listMyEnterprises` / `getEnterprise` / `inviteMember` / `listEnterpriseMembers` / `listOrgSubscriptions` / `listSeats` / `assignSeat` / `revokeSeat` / `getOrgConsumeReport`。OWNER/ADMIN 权限下席位月度变更 ≤ 3 次(超出返 41xxx 业务码);订阅 + 席位 + 用量报表三视图齐备。 |
1124
1149
  | 1.8.0 | 稳定版 | **casehall 法律案件咨询域落地(商品化总规划 P5 方案 B)**。新增 `client.casehall.*`:`listLawyers` / `getLawyer` / `submitCaseLead` / `listMyCaseLeads` / `getMyCases` / `bookConsultation` / `listMyConsultations` / `listMyLegalOrders` / `listLegalSKUs`。律师库公开端点(VERIFIED + ACTIVE,PII L3 已脱敏)+ 案件线索 + 咨询 + 5 LEGAL_SERVICE SKU;admin 板块 9 模块不在 SDK 边界。 |
1125
1150
  | 1.7.0 | 稳定版 | **subscription + pricing + products 三域落地(商品化总规划 P1-P4)**。`subscription`:`listPlans` / `listUserSubscriptions`(订阅档位 + 用户订阅)。`pricing`:`getPricingConfig` / `quoteCompliance`(公开业务参数 + csign 合规 SKU 报价)。`products`:`getProductBySlug` / `listProductsByFamily` / `listComplianceSkus` / `listPublicModels`(商品中心 productFamily / audience / billingMode 索引)。 |
1126
- | 1.6.0 | 稳定版 | `ChatRequest.endUserId` 业务侧终端用户稳定标识,跨 provider 通用语义;SDK 自动按 wire-format 注入(OpenAI 顶层 `user_id` / Anthropic `metadata.user_id`);不传时网关从认证身份 HMAC-SHA256 自动派生 32 字符 id。`validateEndUserId(s)` helper 校验 PII / 长度 / 字符集。SSE keep-alive + 11 分钟超时调优;网关侧命中三项隔离能力(内容安全 / KV-cache / 调度)。 |
1151
+ | 1.6.0 | 稳定版 | `ChatRequest.endUserId` 业务侧终端用户稳定标识,跨 provider 通用语义;SDK 自动按 wire-format 注入(OpenAI 顶层 `user_id` / Anthropic `metadata.user_id`);不传时网关从认证身份 HMAC-SHA256 自动派生 32 字符 id。`validateEndUserId(s)` helper 校验 PII / 长度 / 字符集。SSE keep-alive 注释行显式跳过;网关侧命中三项隔离能力(内容安全 / KV-cache / 调度)。**订正(2026-08-06)**:本行原写"11 分钟超时调优",实际该次改动只建了外层 `AbortController`、未下传给 `doJSONFullRaw`,内层 30 秒默认值始终生效 —— **该调优直到 2.16.0 才真正落地**。 |
1127
1152
  | 1.5.1 | 历史稳定版 | **Docs / examples / 源码注释全量复核与修订 — 无 API 变化**。修补 8 项漂移与遗漏:README API 总览补 25+ 漏列方法(Chat 内部方法、Auth 浏览器 Web OAuth 4 原语、Skills/Notifications/Entitlements/Packages 全量、WS `connect/disconnect/isConnected`);重写 §"手动 OAuth" 段对齐 `auth.ts` 真实签名;§"双格式红线" + 三个 chat 示例 `maxTokens` → snake_case `max_tokens`;错误表补 `ModelNotFoundError`;§Agent Runs 补 13 类 stream event 完整表;新增 §`sanitize` 命名空间小节;`docs/compliance.md` 6 处 `Since v1.6/.../1.10` 统一为 `v1.5.0 (originally planned as ...)`;手册 §7 scope 数 12 → 15 + 新增 S1-S6 rollup 段;`examples/compliance-evidence-timestamp.ts` 补 `ScopeComplianceReportsWrite`(v1.3.2 漂移生产 401 隐患);`examples/auth-oauth-flow.ts` + `examples/core-chat.ts` 注释对齐当前契约;`src/index.ts` + `src/browser.ts` + `src/auth/auth.ts` 注释从 Go-port 语义改为"TS 主实现 + Web OAuth 替代品"。`typecheck` / `lint` / `vitest`(214) / `build` / `test:pack` 全绿。 |
1128
1153
  | 1.5.0 | 稳定版 | 沉淀 `src/shared/` 跨域共享 DTO(`PageRequest`/`PageResult` 别名、`OperationId`/`OperationStatus`/`IdempotencyKeyHeader`、`RetryAdvice` 叠加层、`PrincipalRef`/`TenantRef`、`FeatureGateStatus`/`StepUpStatus`/`BillingPreflightResult`)。**同时全量 rollup compliance gateway S1-S6** 能力(原 1.6.0-1.11.0 roadmap,见 [CHANGELOG.md](./CHANGELOG.md)):S1 6 个分页列表、S2 capabilities + operations 投影、S3 TSA 只读视图、S4 envelope 收尾 + void、S5 合同模板全生命周期 + 2 新 scope(`compliance:contract_template:{read,write}`)、S6 用印执行分页(`listSealUses`)。当前 compliance scope 总数 **15** 个(`complianceScopes()` 返回)。纯增量;8 个平台控制面占位命名空间仍待后端契约就绪后落地。 |
1129
1154
  | 1.4.2 | 稳定版 | `src/` 从扁平 36 文件按业务域重组为 per-domain 目录;公共导出符号集合、`exports`、`dist/` 路径一字未变(纯内部重组)。新增 TypeDoc API 文档。 |
@@ -2288,6 +2288,13 @@ var ErrOAuthCORSBlocked = "oauth_cors_blocked";
2288
2288
  var ErrRefreshProxyFailed = "refresh_proxy_failed";
2289
2289
  var ErrTokenExpired = "token_expired";
2290
2290
  var CHAT_REQUEST_TIMEOUT_MS = 11 * 60 * 1e3;
2291
+ function notifyUpstreamActivity(cb) {
2292
+ if (!cb) return;
2293
+ try {
2294
+ cb();
2295
+ } catch {
2296
+ }
2297
+ }
2291
2298
  var DEFAULT_API_TIMEOUT_MS = 6e4;
2292
2299
  function newDeferred() {
2293
2300
  let resolve;
@@ -3001,7 +3008,13 @@ var Client = class _Client {
3001
3008
  try {
3002
3009
  const { body, adapter } = await this.buildChatRequest(modelID, r, ctl.signal);
3003
3010
  const endpoint = `/managed-models/${encodeURIComponent(modelID)}${adapter.endpointSuffix()}`;
3004
- const { result, headers } = await this.doJSONFullRaw("POST", endpoint, body, ctl.signal);
3011
+ const { result, headers } = await this.doJSONFullRaw(
3012
+ "POST",
3013
+ endpoint,
3014
+ body,
3015
+ ctl.signal,
3016
+ CHAT_REQUEST_TIMEOUT_MS
3017
+ );
3005
3018
  const resp = adapter.parseResponse(result);
3006
3019
  const v1 = headers.get("X-Token-Remaining");
3007
3020
  if (v1) {
@@ -3066,7 +3079,13 @@ var Client = class _Client {
3066
3079
  */
3067
3080
  async generateVideo(modelID, req, signal) {
3068
3081
  const endpoint = `/managed-models/${encodeURIComponent(modelID)}/videos/generations`;
3069
- const { result } = await this.doJSONFullRaw("POST", endpoint, req, signal);
3082
+ const { result } = await this.doJSONFullRaw(
3083
+ "POST",
3084
+ endpoint,
3085
+ req,
3086
+ signal,
3087
+ CHAT_REQUEST_TIMEOUT_MS
3088
+ );
3070
3089
  return this.unwrapAPIResponse(result);
3071
3090
  }
3072
3091
  /**
@@ -3135,7 +3154,8 @@ var Client = class _Client {
3135
3154
  "POST",
3136
3155
  `/managed-models/${encodeURIComponent(modelID)}/anthropic`,
3137
3156
  data,
3138
- ctl.signal
3157
+ ctl.signal,
3158
+ CHAT_REQUEST_TIMEOUT_MS
3139
3159
  );
3140
3160
  const rawStr = new TextDecoder().decode(result);
3141
3161
  try {
@@ -3169,7 +3189,13 @@ var Client = class _Client {
3169
3189
  const body = adapter.buildRequestBody(caps, r);
3170
3190
  const data = JSON.stringify(body);
3171
3191
  const endpoint = `/managed-models/${encodeURIComponent(modelID)}${adapter.endpointSuffix()}`;
3172
- const { result } = await this.doJSONFullRaw("POST", endpoint, data, ctl.signal);
3192
+ const { result } = await this.doJSONFullRaw(
3193
+ "POST",
3194
+ endpoint,
3195
+ data,
3196
+ ctl.signal,
3197
+ CHAT_REQUEST_TIMEOUT_MS
3198
+ );
3173
3199
  const { parseOpenAIResponseToAnthropic: parseOpenAIResponseToAnthropic2 } = await Promise.resolve().then(() => (init_openai(), openai_exports));
3174
3200
  return parseOpenAIResponseToAnthropic2(result);
3175
3201
  } finally {
@@ -3179,23 +3205,27 @@ var Client = class _Client {
3179
3205
  /**
3180
3206
  * 流式聊天 (SSE), 通过 async generator 返回事件
3181
3207
  * v0.5.0: 根据 adapter 路由端点
3208
+ *
3209
+ * @param onUpstreamActivity 见 {@link UpstreamActivityCallback}
3182
3210
  */
3183
- chatStream(modelID, req, signal) {
3211
+ chatStream(modelID, req, signal, onUpstreamActivity) {
3184
3212
  return {
3185
- [Symbol.asyncIterator]: () => this.chatStreamGen(modelID, req, signal, false)
3213
+ [Symbol.asyncIterator]: () => this.chatStreamGen(modelID, req, signal, false, onUpstreamActivity)
3186
3214
  };
3187
3215
  }
3188
3216
  /**
3189
3217
  * Anthropic 原生格式流式聊天 (SSE)
3190
3218
  * 调用 POST /managed-models/:id/anthropic, SSE 事件为 Anthropic 协议格式
3191
3219
  * 无 started/settled/failed 自定义事件, 无 data: [DONE], message_stop 为自然结束
3220
+ *
3221
+ * @param onUpstreamActivity 见 {@link UpstreamActivityCallback}
3192
3222
  */
3193
- chatMessagesStream(modelID, req, signal) {
3223
+ chatMessagesStream(modelID, req, signal, onUpstreamActivity) {
3194
3224
  return {
3195
- [Symbol.asyncIterator]: () => this.chatMessagesStreamGen(modelID, req, signal, false)
3225
+ [Symbol.asyncIterator]: () => this.chatMessagesStreamGen(modelID, req, signal, false, onUpstreamActivity)
3196
3226
  };
3197
3227
  }
3198
- async *chatStreamGen(modelID, req, signal, retried) {
3228
+ async *chatStreamGen(modelID, req, signal, retried, onUpstreamActivity) {
3199
3229
  const r = { ...req, stream: true };
3200
3230
  const { body, adapter } = await this.buildChatRequest(modelID, r, signal);
3201
3231
  const token = await this.ensureToken(signal);
@@ -3228,7 +3258,7 @@ var Client = class _Client {
3228
3258
  `stream: unauthorized and refresh failed: ${refreshErr instanceof Error ? refreshErr.message : String(refreshErr)}`
3229
3259
  );
3230
3260
  }
3231
- yield* this.chatStreamGen(modelID, req, signal, true);
3261
+ yield* this.chatStreamGen(modelID, req, signal, true, onUpstreamActivity);
3232
3262
  return;
3233
3263
  }
3234
3264
  if (!resp.ok) {
@@ -3244,6 +3274,7 @@ var Client = class _Client {
3244
3274
  }
3245
3275
  let currentEvent = "";
3246
3276
  for await (const line of iterSSELines(resp.body)) {
3277
+ notifyUpstreamActivity(onUpstreamActivity);
3247
3278
  if (isSSECommentLine(line)) continue;
3248
3279
  if (line.startsWith("event:")) {
3249
3280
  currentEvent = line.slice("event:".length).trim();
@@ -3264,7 +3295,7 @@ var Client = class _Client {
3264
3295
  }
3265
3296
  }
3266
3297
  }
3267
- async *chatMessagesStreamGen(modelID, req, signal, retried) {
3298
+ async *chatMessagesStreamGen(modelID, req, signal, retried, onUpstreamActivity) {
3268
3299
  const r = { ...req, stream: true };
3269
3300
  const { body, adapter } = await this.buildChatRequest(modelID, r, signal);
3270
3301
  const token = await this.ensureToken(signal);
@@ -3297,7 +3328,7 @@ var Client = class _Client {
3297
3328
  `messages stream: unauthorized and refresh failed: ${refreshErr instanceof Error ? refreshErr.message : String(refreshErr)}`
3298
3329
  );
3299
3330
  }
3300
- yield* this.chatMessagesStreamGen(modelID, req, signal, true);
3331
+ yield* this.chatMessagesStreamGen(modelID, req, signal, true, onUpstreamActivity);
3301
3332
  return;
3302
3333
  }
3303
3334
  if (!resp.ok) {
@@ -3310,6 +3341,7 @@ var Client = class _Client {
3310
3341
  if (adapter.format() === 1 /* OpenAI */) {
3311
3342
  const converter = newOpenAIStreamConverter();
3312
3343
  for await (const line of iterSSELines(resp.body)) {
3344
+ notifyUpstreamActivity(onUpstreamActivity);
3313
3345
  if (isSSECommentLine(line)) continue;
3314
3346
  if (line.startsWith("event:")) {
3315
3347
  line.slice("event:".length).trim();
@@ -3324,6 +3356,7 @@ var Client = class _Client {
3324
3356
  const blockTypeMap = /* @__PURE__ */ new Map();
3325
3357
  let currentEvent = "";
3326
3358
  for await (const line of iterSSELines(resp.body)) {
3359
+ notifyUpstreamActivity(onUpstreamActivity);
3327
3360
  if (isSSECommentLine(line)) continue;
3328
3361
  if (line.startsWith("event:")) {
3329
3362
  currentEvent = line.slice("event:".length).trim();
@@ -3456,7 +3489,19 @@ var Client = class _Client {
3456
3489
  ctl.dispose();
3457
3490
  }
3458
3491
  }
3459
- /** doJSONFull 的 raw bytes 变体 (chat 用, 不立即 JSON.parse) */
3492
+ /**
3493
+ * doJSONFull 的 raw bytes 变体 (chat 用, 不立即 JSON.parse)
3494
+ *
3495
+ * ⚠️ 契约 (2026-08-06): `timeoutMs` 的 30s 默认值只适用于**控制面**端点 (列目录 /
3496
+ * 查配额 / 取任务状态)。凡走**模型推理或生成**的端点 —— chat / anthropic /
3497
+ * embeddings / rerank / images / videos —— 一律必须显式传入 `CHAT_REQUEST_TIMEOUT_MS`,
3498
+ * 哪怕调用方已经用 `withRequestTimeout` 建了外层预算: 外层只约束 `signal`, 内层
3499
+ * 会**另建**一个 `timeoutMs` 计时器, 30s 恒先于任何更长的外层预算触发。
3500
+ *
3501
+ * 这不是假设 —— 2026-08-06 事故里 chat 路径正因漏传本参数而被恒定钉死在 30s,
3502
+ * 且上方 v1.6.0 的注释还声称它已是 11min。回归闸门见
3503
+ * `tests/chat-timeout-budget.test.ts`。
3504
+ */
3460
3505
  async doJSONFullRaw(method, path, body, signal, timeoutMs = 3e4) {
3461
3506
  return this.doJSONFullRawInternal(method, path, body, signal, false, timeoutMs);
3462
3507
  }
@@ -7117,6 +7162,15 @@ function sleep2(ms, signal) {
7117
7162
  }
7118
7163
 
7119
7164
  // src/support/bug-report.ts
7165
+ function unwrapBugReport(raw, op, isComplete) {
7166
+ if (raw && isComplete(raw)) return raw;
7167
+ const inner = raw?.data;
7168
+ if (inner && isComplete(inner)) return inner;
7169
+ const keys = raw && typeof raw === "object" ? Object.keys(raw) : [];
7170
+ throw new Error(
7171
+ `acosmi: ${op}: gateway accepted the request but the response is missing required fields (observed keys: ${keys.length > 0 ? keys.join(",") : "<none>"})`
7172
+ );
7173
+ }
7120
7174
  Client.prototype.submitBugReport = async function(reportData, signal) {
7121
7175
  if (reportData == null) {
7122
7176
  throw new Error("acosmi: reportData required");
@@ -7133,7 +7187,11 @@ Client.prototype.submitBugReport = async function(reportData, signal) {
7133
7187
  { content: contentStr },
7134
7188
  signal
7135
7189
  );
7136
- return result.data;
7190
+ return unwrapBugReport(
7191
+ result,
7192
+ "submitBugReport",
7193
+ (r) => typeof r.feedback_id === "string" && r.feedback_id.length > 0
7194
+ );
7137
7195
  };
7138
7196
  Client.prototype.getBugReport = async function(bugID, signal) {
7139
7197
  const trimmed = bugID.trim();
@@ -7146,7 +7204,7 @@ Client.prototype.getBugReport = async function(bugID, signal) {
7146
7204
  null,
7147
7205
  signal
7148
7206
  );
7149
- return resp.data;
7207
+ return unwrapBugReport(resp, "getBugReport", (r) => typeof r.id === "string");
7150
7208
  };
7151
7209
 
7152
7210
  // src/subscription/client.ts
@@ -7728,6 +7786,6 @@ function brandCredential(c) {
7728
7786
  return c;
7729
7787
  }
7730
7788
 
7731
- export { AGENT_RUN_META_TITLE, AGENT_RUN_META_WORKSPACE, ALL_INTEGRATION_STATUS, ALL_PLATFORMS, ALL_REGIONS, AgentRunStreamError, AgentRunsClient, AnthropicAdapter, AudienceEnum, BillingModeEnum, BucketClassCommercial, BucketClassGeneric, BusinessError, 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, 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, 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 };
7789
+ 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, 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, 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 };
7732
7790
  //# sourceMappingURL=index.mjs.map
7733
7791
  //# sourceMappingURL=index.mjs.map