@acosmi/sdk-ts 2.19.3 → 2.19.5

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.mjs CHANGED
@@ -148,6 +148,14 @@ var init_types = __esm({
148
148
  });
149
149
 
150
150
  // src/shared/errors.ts
151
+ function finiteNonNegative(value) {
152
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : void 0;
153
+ }
154
+ function isStreamError(err) {
155
+ if (err == null || typeof err !== "object") return false;
156
+ const e = err;
157
+ return e.name === "StreamError" && typeof e.errorCode === "string";
158
+ }
151
159
  function nullableID(value) {
152
160
  return value === null || typeof value === "string";
153
161
  }
@@ -357,8 +365,23 @@ var init_errors = __esm({
357
365
  userMessage;
358
366
  /** gateway 原始 error 字符串 */
359
367
  rawError;
360
- /** 客户端是否值得重试 */
368
+ /** 客户端是否值得重试 (= 服务端 `retryable` **且** `requestDisposition === 'not_accepted'`) */
361
369
  retryable;
370
+ /**
371
+ * 服务端在帧上声明的 `retryable` **原值** (2.19.5 起) —— 不与 requestDisposition 合取,
372
+ * 缺席即 undefined。
373
+ *
374
+ * 为什么要并列存一份: 上面的 `retryable` 是两个判据的合取, 网关的流内错误帧并不总是
375
+ * 下发 `requestDisposition`, 于是"服务端明说可重试"会被合取成 false —— 两端各自正确,
376
+ * 合起来恒否。消费方要区分**「服务端明说不可重试」**(false, 一票否决) 与**「服务端没说」**
377
+ * (undefined, 回落到自己的本地分类表) 时, 只能读这个原值; 读 `retryable` 两种情形不可分。
378
+ */
379
+ serverRetryable;
380
+ /**
381
+ * 服务端建议的等待秒数 (2.19.5 起)。**有限非负数**才收, 其余 (null / 负数 /
382
+ * NaN / Infinity / 非数字) 一律 undefined —— 宁可不给, 绝不编造等待时间。
383
+ */
384
+ retryAfterSecs;
362
385
  errorContractVersion;
363
386
  faultDomain;
364
387
  requestDisposition;
@@ -381,6 +404,8 @@ var init_errors = __esm({
381
404
  this.userMessage = userMessage;
382
405
  this.rawError = rawError;
383
406
  this.retryable = retryable;
407
+ this.serverRetryable = opts.retryable;
408
+ this.retryAfterSecs = finiteNonNegative(opts.retryAfterSecs);
384
409
  this.errorContractVersion = opts.errorContractVersion;
385
410
  this.faultDomain = opts.faultDomain;
386
411
  this.requestDisposition = opts.requestDisposition;
@@ -405,272 +430,15 @@ var init_errors = __esm({
405
430
  }
406
431
  });
407
432
 
408
- // src/models/betas.ts
409
- function buildBetas(caps, req) {
410
- const betas = [];
411
- if (caps.supports_isp) {
412
- betas.push(betaInterleavedThinking);
413
- betas.push(betaContextManagement);
414
- }
415
- if (caps.supports_redact_thinking && req.thinking && req.thinking.display === "summary") {
416
- betas.push(betaRedactThinking);
417
- }
418
- if (caps.supports_1m_context) {
419
- betas.push(betaContext1M);
420
- }
421
- const hasStructuredOutput = caps.supports_structured_output && req.outputConfig != null;
422
- if (hasStructuredOutput) {
423
- betas.push(betaStructuredOutputs);
424
- } else if (caps.supports_token_efficient) {
425
- betas.push(betaTokenEfficientTools);
426
- }
427
- if (caps.supports_tool_search) {
428
- betas.push(betaAdvancedToolUse);
429
- }
430
- const needsEffort = req.effort != null || req.thinking != null && req.thinking.level && req.thinking.level !== ThinkingOff;
431
- if (caps.supports_effort && needsEffort) {
432
- betas.push(betaEffort);
433
- }
434
- if (caps.supports_fast_mode && req.speed === "fast") {
435
- betas.push(betaFastMode);
436
- }
437
- if (caps.supports_prompt_cache) {
438
- betas.push(betaPromptCachingScope);
439
- }
440
- return uniqueMerge(betas, req.betas ?? []);
441
- }
442
- function uniqueMerge(base, extra) {
443
- if (extra.length === 0) return base;
444
- const seen = new Set(base);
445
- for (const s of extra) {
446
- if (!seen.has(s)) {
447
- base.push(s);
448
- seen.add(s);
449
- }
450
- }
451
- return base;
452
- }
453
- var betaInterleavedThinking, betaContext1M, betaContextManagement, betaStructuredOutputs, betaAdvancedToolUse, betaEffort, betaPromptCachingScope, betaFastMode, betaRedactThinking, betaTokenEfficientTools;
454
- var init_betas = __esm({
455
- "src/models/betas.ts"() {
456
- init_types();
457
- betaInterleavedThinking = "interleaved-thinking-2025-05-14";
458
- betaContext1M = "context-1m-2025-08-07";
459
- betaContextManagement = "context-management-2025-06-27";
460
- betaStructuredOutputs = "structured-outputs-2025-11-13";
461
- betaAdvancedToolUse = "advanced-tool-use-2025-11-20";
462
- betaEffort = "effort-2025-11-24";
463
- betaPromptCachingScope = "prompt-caching-scope-2026-01-05";
464
- betaFastMode = "fast-mode-2026-02-01";
465
- betaRedactThinking = "redact-thinking-2026-02-12";
466
- betaTokenEfficientTools = "token-efficient-tools-2025-02-19";
467
- }
468
- });
469
-
470
- // src/models/adapters/anthropic.ts
471
- function resolveThinkingLevel(body, req, caps) {
472
- const level = req.thinking?.level ?? "";
473
- if (level === ThinkingOff) {
474
- body["thinking"] = { type: "disabled" };
475
- return;
476
- }
477
- if (!caps.supports_adaptive_thinking && !caps.supports_thinking) {
478
- return;
479
- }
480
- let maxTokens = req.max_tokens ?? 0;
481
- if (maxTokens <= 0) {
482
- maxTokens = ThinkingHighMinMaxTokens;
483
- }
484
- if (level === ThinkingMax) {
485
- let modelMax = caps.max_output_tokens;
486
- if (modelMax <= 0) modelMax = ThinkingMaxFallbackMaxTokens;
487
- if (maxTokens < modelMax) maxTokens = modelMax;
488
- } else {
489
- if (maxTokens < ThinkingHighMinMaxTokens) maxTokens = ThinkingHighMinMaxTokens;
490
- }
491
- body["max_tokens"] = maxTokens;
492
- if (caps.supports_adaptive_thinking) {
493
- const thinking = { type: "adaptive" };
494
- if (req.thinking?.display) thinking["display"] = req.thinking.display;
495
- body["thinking"] = thinking;
496
- } else if (caps.supports_thinking) {
497
- let budget = maxTokens - 1;
498
- if (budget < 1024) budget = 1024;
499
- const thinking = {
500
- type: "enabled",
501
- budget_tokens: budget
502
- };
503
- if (req.thinking?.display) thinking["display"] = req.thinking.display;
504
- body["thinking"] = thinking;
505
- }
506
- if (caps.supports_effort) {
507
- let effortLevel = "high";
508
- if (level === "low") effortLevel = "low";
509
- if (level === "medium" || level === "xhigh") effortLevel = level;
510
- if (level === ThinkingMax && caps.supports_max_effort) {
511
- effortLevel = "max";
512
- }
513
- body["effort"] = { level: effortLevel };
514
- }
515
- delete body["temperature"];
516
- }
517
- var ANTHROPIC_SDK_MANAGED_BODY_KEYS, AnthropicAdapter;
518
- var init_anthropic = __esm({
519
- "src/models/adapters/anthropic.ts"() {
520
- init_types();
521
- init_errors();
522
- init_betas();
523
- init_adapters();
524
- ANTHROPIC_SDK_MANAGED_BODY_KEYS = /* @__PURE__ */ new Set([
525
- "thinking",
526
- "effort",
527
- "max_tokens",
528
- "temperature",
529
- "betas"
530
- ]);
531
- AnthropicAdapter = class {
532
- format() {
533
- return 0 /* Anthropic */;
534
- }
535
- endpointSuffix() {
536
- return "/anthropic";
537
- }
538
- /**
539
- * 构建 Anthropic 格式请求体
540
- * 逻辑等同于原 buildChatRequest, 包含完整的 betas/tools/serverTools/extraBody 处理
541
- */
542
- buildRequestBody(caps, req) {
543
- const body = {};
544
- if (req.rawMessages != null) {
545
- body["messages"] = req.rawMessages;
546
- } else if ((req.messages?.length ?? 0) > 0) {
547
- body["messages"] = req.messages;
548
- }
549
- body["stream"] = req.stream === true;
550
- if (req.max_tokens && req.max_tokens > 0) {
551
- body["max_tokens"] = req.max_tokens;
552
- }
553
- if (req.system != null) {
554
- body["system"] = req.system;
555
- }
556
- if (req.temperature != null) {
557
- body["temperature"] = req.temperature;
558
- }
559
- if (req.thinking && req.thinking.level && req.thinking.level !== "") {
560
- resolveThinkingLevel(body, req, caps);
561
- } else {
562
- if (req.thinking) {
563
- body["thinking"] = req.thinking;
564
- }
565
- if (req.effort) {
566
- body["effort"] = req.effort;
567
- }
568
- }
569
- if (req.metadata || req.endUserId && req.endUserId !== "") {
570
- const meta = {};
571
- if (req.metadata) {
572
- for (const [k, v] of Object.entries(req.metadata)) {
573
- meta[k] = v;
574
- }
575
- }
576
- if (req.endUserId && req.endUserId !== "" && meta["user_id"] === void 0) {
577
- meta["user_id"] = req.endUserId;
578
- }
579
- body["metadata"] = meta;
580
- }
581
- const allTools = [];
582
- if (req.tools != null) {
583
- try {
584
- const parsed = JSON.parse(JSON.stringify(req.tools));
585
- if (Array.isArray(parsed)) {
586
- for (const t of parsed) allTools.push(t);
587
- }
588
- } catch {
589
- }
590
- }
591
- for (const st of req.serverTools ?? []) {
592
- const schema = {
593
- type: st.type,
594
- name: st.name
595
- };
596
- if (st.config) {
597
- for (const [k, v] of Object.entries(st.config)) {
598
- schema[k] = v;
599
- }
600
- }
601
- allTools.push(schema);
602
- }
603
- if (allTools.length > 0) {
604
- body["tools"] = allTools;
605
- }
606
- if (req.speed && req.speed !== "") {
607
- body["speed"] = req.speed;
608
- }
609
- if (req.outputConfig) {
610
- body["output_config"] = req.outputConfig;
611
- }
612
- const betas = buildBetas(caps, req);
613
- if (betas.length > 0) {
614
- body["betas"] = betas;
615
- }
616
- if (req.extraBody) {
617
- for (const [k, v] of Object.entries(req.extraBody)) {
618
- if (ANTHROPIC_SDK_MANAGED_BODY_KEYS.has(k)) {
619
- console.warn(
620
- `acosmi-sdk: extraBody key "${k}" is SDK-managed and was ignored (use the dedicated request field instead).`
621
- );
622
- continue;
623
- }
624
- body[k] = v;
625
- }
626
- }
627
- return body;
628
- }
629
- /**
630
- * 解析 Anthropic 格式同步响应
631
- * 兼容 APIResponse 包装 {"code":0,"data":{...}} 和裸 Anthropic JSON 两种格式
632
- */
633
- parseResponse(bodyInput) {
634
- const bodyStr = typeof bodyInput === "string" ? bodyInput : new TextDecoder().decode(bodyInput);
635
- let raw = bodyStr;
636
- try {
637
- const wrapper = JSON.parse(bodyStr);
638
- if (wrapper.data != null && wrapper.data !== null) {
639
- if ((wrapper.code ?? 0) !== 0) {
640
- throw new BusinessError(wrapper.code ?? 0, wrapper.message ?? "");
641
- }
642
- raw = JSON.stringify(wrapper.data);
643
- }
644
- } catch (e) {
645
- if (e instanceof BusinessError) throw e;
646
- }
647
- let resp;
648
- try {
649
- resp = JSON.parse(raw);
650
- } catch (e) {
651
- throw new Error(
652
- `decode anthropic response: ${e instanceof Error ? e.message : String(e)}`
653
- );
654
- }
655
- resp.tokenRemaining = -1;
656
- resp.callRemaining = -1;
657
- resp.modelTokenRemaining = -1;
658
- resp.modelTokenRemainingETU = -1;
659
- return resp;
660
- }
661
- /**
662
- * 解析 Anthropic SSE 行
663
- *
664
- * Anthropic 原生协议无 [DONE] (message_stop 后上游关闭连接),
665
- * 但 Nexus Gateway 的 ChatStream 路径会追加 [DONE] 哨兵, 此处一并处理。
666
- */
667
- parseStreamLine(eventType, data) {
668
- if (data === "[DONE]") {
669
- return { event: { event: "", data: "" }, done: true };
670
- }
671
- return { event: { event: eventType, data }, done: false };
672
- }
673
- };
433
+ // src/models/adapters/format.ts
434
+ var ProviderFormat;
435
+ var init_format = __esm({
436
+ "src/models/adapters/format.ts"() {
437
+ ProviderFormat = /* @__PURE__ */ ((ProviderFormat2) => {
438
+ ProviderFormat2[ProviderFormat2["Anthropic"] = 0] = "Anthropic";
439
+ ProviderFormat2[ProviderFormat2["OpenAI"] = 1] = "OpenAI";
440
+ return ProviderFormat2;
441
+ })(ProviderFormat || {});
674
442
  }
675
443
  });
676
444
 
@@ -743,16 +511,19 @@ function convertOpenAIToChatResponse(oai) {
743
511
  role: "assistant",
744
512
  content: [],
745
513
  stop_reason: "",
514
+ // [W-SDK-OPENAI-PARITY] 缺 usage 的响应按 0 计数, 而不是让 `oai.usage.prompt_tokens`
515
+ // 抛 TypeError 把整条响应打死 —— 上游不计量是常见形态, 正文照样是有效的。
516
+ // 与 Go 侧同名函数逐字同语义 (那里 Usage 是值类型, 缺席即零值)。
746
517
  usage: {
747
- input_tokens: oai.usage.prompt_tokens,
748
- output_tokens: oai.usage.completion_tokens
518
+ input_tokens: oai.usage?.prompt_tokens ?? 0,
519
+ output_tokens: oai.usage?.completion_tokens ?? 0
749
520
  },
750
521
  tokenRemaining: -1,
751
522
  callRemaining: -1,
752
523
  modelTokenRemaining: -1,
753
524
  modelTokenRemainingETU: -1
754
525
  };
755
- if (oai.choices.length > 0) {
526
+ if (Array.isArray(oai.choices) && oai.choices.length > 0) {
756
527
  const choice = oai.choices[0];
757
528
  switch (choice.finish_reason) {
758
529
  case "stop":
@@ -826,12 +597,14 @@ function parseOpenAIResponseToAnthropic(raw) {
826
597
  content: [],
827
598
  model: oaiResp.model,
828
599
  stop_reason: "",
600
+ // [W-SDK-OPENAI-PARITY] 同 convertOpenAIToChatResponse: 缺 usage 按 0 计数, 不抛。
601
+ // 两处都要改 —— 只改一处等于「非流式路径修好了一半」, 而两条路径是同一族上游响应。
829
602
  usage: {
830
- input_tokens: oaiResp.usage.prompt_tokens,
831
- output_tokens: oaiResp.usage.completion_tokens
603
+ input_tokens: oaiResp.usage?.prompt_tokens ?? 0,
604
+ output_tokens: oaiResp.usage?.completion_tokens ?? 0
832
605
  }
833
606
  };
834
- if (oaiResp.choices.length > 0) {
607
+ if (Array.isArray(oaiResp.choices) && oaiResp.choices.length > 0) {
835
608
  const choice = oaiResp.choices[0];
836
609
  switch (choice.finish_reason) {
837
610
  case "stop":
@@ -869,6 +642,21 @@ function parseOpenAIResponseToAnthropic(raw) {
869
642
  }
870
643
  return resp;
871
644
  }
645
+ function readStreamUsage(chunk) {
646
+ const raw = chunk.usage;
647
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
648
+ return null;
649
+ }
650
+ const { prompt_tokens: promptTokens, completion_tokens: completionTokens } = raw;
651
+ const usage = {};
652
+ if (typeof promptTokens === "number" && Number.isFinite(promptTokens)) {
653
+ usage.input_tokens = promptTokens;
654
+ }
655
+ if (typeof completionTokens === "number" && Number.isFinite(completionTokens)) {
656
+ usage.output_tokens = completionTokens;
657
+ }
658
+ return usage;
659
+ }
872
660
  function newOpenAIStreamConverter() {
873
661
  return new OpenAIStreamConverter();
874
662
  }
@@ -877,7 +665,7 @@ var init_openai = __esm({
877
665
  "src/models/adapters/openai.ts"() {
878
666
  init_types();
879
667
  init_errors();
880
- init_adapters();
668
+ init_format();
881
669
  OpenAIAdapter = class {
882
670
  format() {
883
671
  return 1 /* OpenAI */;
@@ -1002,8 +790,18 @@ var init_openai = __esm({
1002
790
  toolArgsAccum = /* @__PURE__ */ new Map();
1003
791
  /** 上一次解析出的 tool 键,供缺 index 且缺 id 的后续增量沿用。 */
1004
792
  lastToolKey = null;
1005
- /** 已发出 message_delta/message_stop,避免 finish_reason 与 `[DONE]` 各收一次。 */
793
+ /** 已发出 message_delta/message_stop,避免 finish_reason、usage 尾帧、`[DONE]` 与
794
+ * {@link flush} 重复收口 —— 整条流恰好一个 message_stop。 */
1006
795
  messageClosed = false;
796
+ /** 已为仍打开的块发出 content_block_stop。与 {@link messageClosed} 分开记:块在
797
+ * finish_reason 帧上就关,message_delta/message_stop 却可能推迟到之后的帧。 */
798
+ blocksClosed = false;
799
+ /** [W-QUAD-CHAIN-20260914] finish_reason 已到、但 message_delta/message_stop 因等待
800
+ * usage 尾帧而推迟时记下的 stop_reason;没有推迟中的收尾时为 null。 */
801
+ pendingStopReason = null;
802
+ /** [W-QUAD-CHAIN-20260914] 最近一次带 usage 对象的帧搬出的 usage(后到覆盖先到);
803
+ * 整条流从未出现 usage 对象时为 null,收尾 message_delta 据此不写 usage 键。 */
804
+ usage = null;
1007
805
  /**
1008
806
  * 解析一条 tool_call delta 归属的块键。
1009
807
  *
@@ -1028,15 +826,18 @@ var init_openai = __esm({
1028
826
  return 0;
1029
827
  }
1030
828
  /**
1031
- * 关闭仍打开的 text / thinking / tool 块,并收口 message。
829
+ * 关闭仍打开的 text / thinking / tool 块(整条流只关一次)。
1032
830
  *
1033
831
  * 由 `finish_reason` 分支与 `[DONE]` 分支共用:上游断流或只发 `[DONE]` 而不发
1034
832
  * `finish_reason` 时,此前一个 `content_block_stop` 都不会发,下游拿到的是一个
1035
833
  * 永不闭合的 tool_use 块。
834
+ *
835
+ * [W-QUAD-CHAIN-20260914] 此前关块与 message_delta/message_stop 是同一个方法里同一时刻
836
+ * 的事;usage 尾帧要求收尾推迟,于是拆成本方法与 {@link emitMessageEnd} 两段,各自防重。
1036
837
  */
1037
- closeOpenBlocks(events, stopReason) {
1038
- if (this.messageClosed) return;
1039
- this.messageClosed = true;
838
+ closeContentBlocks(events) {
839
+ if (this.blocksClosed) return;
840
+ this.blocksClosed = true;
1040
841
  if (this.textStarted) {
1041
842
  events.push({
1042
843
  event: "content_block_stop",
@@ -1056,10 +857,23 @@ var init_openai = __esm({
1056
857
  data: JSON.stringify({ type: "content_block_stop", index: idx })
1057
858
  });
1058
859
  }
1059
- events.push({
1060
- event: "message_delta",
1061
- data: JSON.stringify({ type: "message_delta", delta: { stop_reason: stopReason } })
1062
- });
860
+ }
861
+ /**
862
+ * 发出 message_delta + message_stop,整条流只发一次;同时清掉推迟中的收尾。
863
+ *
864
+ * 见过 usage 对象就把它放进 message_delta:usage 必须出现在唯一的 message_stop 之前,
865
+ * message_stop 之后下游已无处安放用量。整条流从未出现 usage 对象时不写 usage 键 ——
866
+ * 缺席表示「上游没给」,不是 0。
867
+ */
868
+ emitMessageEnd(events, stopReason) {
869
+ if (this.messageClosed) return;
870
+ this.messageClosed = true;
871
+ this.pendingStopReason = null;
872
+ const messageDelta = { type: "message_delta", delta: { stop_reason: stopReason } };
873
+ if (this.usage !== null) {
874
+ messageDelta.usage = this.usage;
875
+ }
876
+ events.push({ event: "message_delta", data: JSON.stringify(messageDelta) });
1063
877
  events.push({
1064
878
  event: "message_stop",
1065
879
  data: JSON.stringify({ type: "message_stop" })
@@ -1072,8 +886,11 @@ var init_openai = __esm({
1072
886
  convert(data) {
1073
887
  if (data === "[DONE]") {
1074
888
  const events2 = [];
1075
- if (this.messageStarted) {
1076
- this.closeOpenBlocks(events2, "end_turn");
889
+ if (this.pendingStopReason !== null) {
890
+ this.emitMessageEnd(events2, this.pendingStopReason);
891
+ } else if (this.messageStarted) {
892
+ this.closeContentBlocks(events2);
893
+ this.emitMessageEnd(events2, "end_turn");
1077
894
  }
1078
895
  return { events: events2, done: true };
1079
896
  }
@@ -1084,10 +901,18 @@ var init_openai = __esm({
1084
901
  throw new Error(`parse openai stream chunk: ${e instanceof Error ? e.message : String(e)}`);
1085
902
  }
1086
903
  const events = [];
904
+ const frameUsage = readStreamUsage(chunk);
905
+ if (frameUsage !== null) {
906
+ this.usage = frameUsage;
907
+ }
1087
908
  if (!Array.isArray(chunk.choices) || chunk.choices.length === 0) {
909
+ if (frameUsage !== null && this.pendingStopReason !== null) {
910
+ this.emitMessageEnd(events, this.pendingStopReason);
911
+ }
1088
912
  return { events, done: false };
1089
913
  }
1090
914
  const choice = chunk.choices[0];
915
+ const delta = choice.delta ?? {};
1091
916
  if (!this.messageStarted) {
1092
917
  this.messageStarted = true;
1093
918
  const msgJSON = JSON.stringify({
@@ -1102,8 +927,17 @@ var init_openai = __esm({
1102
927
  });
1103
928
  events.push({ event: "message_start", data: msgJSON });
1104
929
  }
1105
- if (choice.delta.reasoning_content && choice.delta.reasoning_content !== "") {
930
+ if (delta.reasoning_content && delta.reasoning_content !== "") {
1106
931
  if (!this.thinkingStarted) {
932
+ if (this.textStarted) {
933
+ const stopJSON = JSON.stringify({
934
+ type: "content_block_stop",
935
+ index: this.blockIndex
936
+ });
937
+ events.push({ event: "content_block_stop", data: stopJSON });
938
+ this.blockIndex++;
939
+ this.textStarted = false;
940
+ }
1107
941
  this.thinkingStarted = true;
1108
942
  this.thinkingBlockIndex = this.blockIndex;
1109
943
  const blockJSON = JSON.stringify({
@@ -1116,11 +950,11 @@ var init_openai = __esm({
1116
950
  const deltaJSON = JSON.stringify({
1117
951
  type: "content_block_delta",
1118
952
  index: this.thinkingBlockIndex,
1119
- delta: { type: "thinking_delta", thinking: choice.delta.reasoning_content }
953
+ delta: { type: "thinking_delta", thinking: delta.reasoning_content }
1120
954
  });
1121
955
  events.push({ event: "content_block_delta", data: deltaJSON });
1122
956
  }
1123
- if (choice.delta.content && choice.delta.content !== "") {
957
+ if (delta.content && delta.content !== "") {
1124
958
  if (this.thinkingStarted && !this.thinkingStopped) {
1125
959
  this.thinkingStopped = true;
1126
960
  const stopJSON = JSON.stringify({
@@ -1142,11 +976,11 @@ var init_openai = __esm({
1142
976
  const deltaJSON = JSON.stringify({
1143
977
  type: "content_block_delta",
1144
978
  index: this.blockIndex,
1145
- delta: { type: "text_delta", text: choice.delta.content }
979
+ delta: { type: "text_delta", text: delta.content }
1146
980
  });
1147
981
  events.push({ event: "content_block_delta", data: deltaJSON });
1148
982
  }
1149
- for (const tc of choice.delta.tool_calls ?? []) {
983
+ for (const tc of delta.tool_calls ?? []) {
1150
984
  const fn = tc.function;
1151
985
  const toolKey = this.resolveToolKey(tc);
1152
986
  if (!this.toolBlockIndex.has(toolKey)) {
@@ -1221,67 +1055,39 @@ var init_openai = __esm({
1221
1055
  default:
1222
1056
  stopReason = choice.finish_reason;
1223
1057
  }
1224
- this.closeOpenBlocks(events, stopReason);
1058
+ if (!this.messageClosed && this.pendingStopReason === null) {
1059
+ this.closeContentBlocks(events);
1060
+ if (this.usage !== null) {
1061
+ this.emitMessageEnd(events, stopReason);
1062
+ } else {
1063
+ this.pendingStopReason = stopReason;
1064
+ }
1065
+ }
1066
+ }
1067
+ if (frameUsage !== null && this.pendingStopReason !== null) {
1068
+ this.emitMessageEnd(events, this.pendingStopReason);
1225
1069
  }
1226
1070
  return { events, done: false };
1227
1071
  }
1072
+ /**
1073
+ * 流在**没有** `[DONE]` 的情况下结束 (EOF) 时, 由驱动方在读循环结束后调用一次。
1074
+ *
1075
+ * 只补发「finish_reason 已到、仅因等待 usage 尾帧而推迟」的 message_delta + message_stop。
1076
+ * 从未收到 finish_reason 的流是被截断的流, 这里刻意**不**替它伪造正常结束 —— 一个
1077
+ * `end_turn` 的 message_stop 会把被截断的回答当成完整回答交给下游。
1078
+ * 已经收口 (usage 帧 / `[DONE]` / 上一次 flush) 后再调用返回空数组, 不会发出第二个 message_stop。
1079
+ */
1080
+ flush() {
1081
+ const events = [];
1082
+ if (this.pendingStopReason !== null) {
1083
+ this.emitMessageEnd(events, this.pendingStopReason);
1084
+ }
1085
+ return events;
1086
+ }
1228
1087
  };
1229
1088
  }
1230
1089
  });
1231
1090
 
1232
- // src/models/adapters/index.ts
1233
- function getAdapter(provider) {
1234
- const a = adapterRegistry[provider.toLowerCase()];
1235
- if (a) return a;
1236
- return defaultOpenAIAdapter;
1237
- }
1238
- function getAdapterForModel(m) {
1239
- let hasAnthropic = false;
1240
- let hasOpenAI = false;
1241
- for (const f of m.supported_formats ?? []) {
1242
- switch (f.trim().toLowerCase()) {
1243
- case "anthropic":
1244
- hasAnthropic = true;
1245
- break;
1246
- case "openai":
1247
- hasOpenAI = true;
1248
- break;
1249
- }
1250
- }
1251
- const declared = hasAnthropic || hasOpenAI;
1252
- const pref = (m.preferred_format ?? "").trim().toLowerCase();
1253
- switch (pref) {
1254
- case "anthropic":
1255
- if (!declared || hasAnthropic) return new AnthropicAdapter();
1256
- break;
1257
- case "openai":
1258
- if (!declared || hasOpenAI) return new OpenAIAdapter();
1259
- break;
1260
- }
1261
- if (hasAnthropic) return new AnthropicAdapter();
1262
- if (hasOpenAI) return new OpenAIAdapter();
1263
- return getAdapter((m.provider ?? "").toLowerCase());
1264
- }
1265
- var ProviderFormat, adapterRegistry, defaultOpenAIAdapter;
1266
- var init_adapters = __esm({
1267
- "src/models/adapters/index.ts"() {
1268
- init_anthropic();
1269
- init_openai();
1270
- init_openai();
1271
- ProviderFormat = /* @__PURE__ */ ((ProviderFormat2) => {
1272
- ProviderFormat2[ProviderFormat2["Anthropic"] = 0] = "Anthropic";
1273
- ProviderFormat2[ProviderFormat2["OpenAI"] = 1] = "OpenAI";
1274
- return ProviderFormat2;
1275
- })(ProviderFormat || {});
1276
- adapterRegistry = {
1277
- anthropic: new AnthropicAdapter(),
1278
- /** Acosmi 自有模型走 Anthropic 格式 */
1279
- acosmi: new AnthropicAdapter()
1280
- };
1281
- defaultOpenAIAdapter = new OpenAIAdapter();
1282
- }
1283
- });
1284
-
1285
1091
  // src/core/credentials.ts
1286
1092
  var uuid = () => globalThis.crypto.randomUUID();
1287
1093
  var pause = () => new Promise((resolve) => setTimeout(resolve, 25));
@@ -2414,7 +2220,10 @@ var FileTokenStore = class {
2414
2220
  /**
2415
2221
  * 跨进程临界区. 用 sidecar `<path>.lock` 文件 + O_EXCL 创建语义实现互斥:
2416
2222
  * - 创建成功 = 持有锁; 写入 pid+timestamp 便于诊断
2417
- * - 创建失败 (EEXIST) = 别的进程持锁, backoff 重试
2223
+ * - 创建失败 (EEXIST) = 别的进程持锁, stale 检测后 backoff 重试
2224
+ * - 创建失败 (Windows 的 EPERM / EBUSY) = 前一持有者的 unlink 处于 delete-pending,
2225
+ * 同属争用; 跳过 stale 检测直接 backoff 重试 (见 catch 内注释)。EACCES 不在其中 —
2226
+ * 它是真权限错误, 立即抛
2418
2227
  * - 锁文件 mtime > staleMs = 进程崩溃残留, unlink 后重试
2419
2228
  * - acquireTimeoutMs 超时 = 抛错 (caller 应作为 transient error 处理, 上层 retry)
2420
2229
  *
@@ -2448,20 +2257,22 @@ ${Date.now()}
2448
2257
  };
2449
2258
  break;
2450
2259
  } catch (e) {
2451
- if (!isAlreadyExistsError(e)) throw e;
2452
- let stale = false;
2453
- try {
2454
- const st = await fs.stat(lockPath);
2455
- if (Date.now() - st.mtimeMs > fileLockDefaults.staleMs) stale = true;
2456
- } catch {
2457
- continue;
2458
- }
2459
- if (stale) {
2260
+ if (!isLockContendedError(e)) throw e;
2261
+ if (!isWindowsLockBusyError(e)) {
2262
+ let stale = false;
2460
2263
  try {
2461
- await fs.unlink(lockPath);
2264
+ const st = await fs.stat(lockPath);
2265
+ if (Date.now() - st.mtimeMs > fileLockDefaults.staleMs) stale = true;
2462
2266
  } catch {
2267
+ continue;
2268
+ }
2269
+ if (stale) {
2270
+ try {
2271
+ await fs.unlink(lockPath);
2272
+ } catch {
2273
+ }
2274
+ continue;
2463
2275
  }
2464
- continue;
2465
2276
  }
2466
2277
  if (Date.now() - startMs > fileLockDefaults.acquireTimeoutMs) {
2467
2278
  throw new Error(
@@ -2567,6 +2378,15 @@ function isNotExistError(e) {
2567
2378
  }
2568
2379
  return false;
2569
2380
  }
2381
+ function isWindowsLockBusyError(e) {
2382
+ if (typeof process === "undefined" || process.platform !== "win32") return false;
2383
+ if (typeof e !== "object" || e === null || !("code" in e)) return false;
2384
+ const code = e.code;
2385
+ return code === "EPERM" || code === "EBUSY";
2386
+ }
2387
+ function isLockContendedError(e) {
2388
+ return isAlreadyExistsError(e) || isWindowsLockBusyError(e);
2389
+ }
2570
2390
  function isAlreadyExistsError(e) {
2571
2391
  if (typeof e === "object" && e !== null && "code" in e) {
2572
2392
  return e.code === "EEXIST";
@@ -2672,8 +2492,308 @@ function computeBackoff(p, attempt, err) {
2672
2492
  return d;
2673
2493
  }
2674
2494
 
2675
- // src/core/client.ts
2676
- init_adapters();
2495
+ // src/models/adapters/anthropic.ts
2496
+ init_types();
2497
+ init_errors();
2498
+
2499
+ // src/models/betas.ts
2500
+ init_types();
2501
+ var betaInterleavedThinking = "interleaved-thinking-2025-05-14";
2502
+ var betaContext1M = "context-1m-2025-08-07";
2503
+ var betaContextManagement = "context-management-2025-06-27";
2504
+ var betaStructuredOutputs = "structured-outputs-2025-11-13";
2505
+ var betaAdvancedToolUse = "advanced-tool-use-2025-11-20";
2506
+ var betaEffort = "effort-2025-11-24";
2507
+ var betaPromptCachingScope = "prompt-caching-scope-2026-01-05";
2508
+ var betaFastMode = "fast-mode-2026-02-01";
2509
+ var betaRedactThinking = "redact-thinking-2026-02-12";
2510
+ var betaTokenEfficientTools = "token-efficient-tools-2025-02-19";
2511
+ function buildBetas(caps, req) {
2512
+ const betas = [];
2513
+ if (caps.supports_isp) {
2514
+ betas.push(betaInterleavedThinking);
2515
+ betas.push(betaContextManagement);
2516
+ }
2517
+ if (caps.supports_redact_thinking && req.thinking && req.thinking.display === "summary") {
2518
+ betas.push(betaRedactThinking);
2519
+ }
2520
+ if (caps.supports_1m_context) {
2521
+ betas.push(betaContext1M);
2522
+ }
2523
+ const hasStructuredOutput = caps.supports_structured_output && req.outputConfig != null;
2524
+ if (hasStructuredOutput) {
2525
+ betas.push(betaStructuredOutputs);
2526
+ } else if (caps.supports_token_efficient) {
2527
+ betas.push(betaTokenEfficientTools);
2528
+ }
2529
+ if (caps.supports_tool_search) {
2530
+ betas.push(betaAdvancedToolUse);
2531
+ }
2532
+ const needsEffort = req.effort != null || req.thinking != null && req.thinking.level && req.thinking.level !== ThinkingOff;
2533
+ if (caps.supports_effort && needsEffort) {
2534
+ betas.push(betaEffort);
2535
+ }
2536
+ if (caps.supports_fast_mode && req.speed === "fast") {
2537
+ betas.push(betaFastMode);
2538
+ }
2539
+ if (caps.supports_prompt_cache) {
2540
+ betas.push(betaPromptCachingScope);
2541
+ }
2542
+ return uniqueMerge(betas, req.betas ?? []);
2543
+ }
2544
+ function uniqueMerge(base, extra) {
2545
+ if (extra.length === 0) return base;
2546
+ const seen = new Set(base);
2547
+ for (const s of extra) {
2548
+ if (!seen.has(s)) {
2549
+ base.push(s);
2550
+ seen.add(s);
2551
+ }
2552
+ }
2553
+ return base;
2554
+ }
2555
+
2556
+ // src/models/adapters/anthropic.ts
2557
+ init_format();
2558
+ var ANTHROPIC_SDK_MANAGED_BODY_KEYS = /* @__PURE__ */ new Set([
2559
+ "thinking",
2560
+ "effort",
2561
+ "max_tokens",
2562
+ "temperature",
2563
+ "betas"
2564
+ ]);
2565
+ var AnthropicAdapter = class {
2566
+ format() {
2567
+ return 0 /* Anthropic */;
2568
+ }
2569
+ endpointSuffix() {
2570
+ return "/anthropic";
2571
+ }
2572
+ /**
2573
+ * 构建 Anthropic 格式请求体
2574
+ * 逻辑等同于原 buildChatRequest, 包含完整的 betas/tools/serverTools/extraBody 处理
2575
+ */
2576
+ buildRequestBody(caps, req) {
2577
+ const body = {};
2578
+ if (req.rawMessages != null) {
2579
+ body["messages"] = req.rawMessages;
2580
+ } else if ((req.messages?.length ?? 0) > 0) {
2581
+ body["messages"] = req.messages;
2582
+ }
2583
+ body["stream"] = req.stream === true;
2584
+ if (req.max_tokens && req.max_tokens > 0) {
2585
+ body["max_tokens"] = req.max_tokens;
2586
+ }
2587
+ if (req.system != null) {
2588
+ body["system"] = req.system;
2589
+ }
2590
+ if (req.temperature != null) {
2591
+ body["temperature"] = req.temperature;
2592
+ }
2593
+ if (req.thinking && req.thinking.level && req.thinking.level !== "") {
2594
+ resolveThinkingLevel(body, req, caps);
2595
+ } else {
2596
+ if (req.thinking) {
2597
+ body["thinking"] = req.thinking;
2598
+ }
2599
+ if (req.effort) {
2600
+ body["effort"] = req.effort;
2601
+ }
2602
+ }
2603
+ if (req.metadata || req.endUserId && req.endUserId !== "") {
2604
+ const meta = {};
2605
+ if (req.metadata) {
2606
+ for (const [k, v] of Object.entries(req.metadata)) {
2607
+ meta[k] = v;
2608
+ }
2609
+ }
2610
+ if (req.endUserId && req.endUserId !== "" && meta["user_id"] === void 0) {
2611
+ meta["user_id"] = req.endUserId;
2612
+ }
2613
+ body["metadata"] = meta;
2614
+ }
2615
+ const allTools = [];
2616
+ if (req.tools != null) {
2617
+ try {
2618
+ const parsed = JSON.parse(JSON.stringify(req.tools));
2619
+ if (Array.isArray(parsed)) {
2620
+ for (const t of parsed) allTools.push(t);
2621
+ }
2622
+ } catch {
2623
+ }
2624
+ }
2625
+ for (const st of req.serverTools ?? []) {
2626
+ const schema = {
2627
+ type: st.type,
2628
+ name: st.name
2629
+ };
2630
+ if (st.config) {
2631
+ for (const [k, v] of Object.entries(st.config)) {
2632
+ schema[k] = v;
2633
+ }
2634
+ }
2635
+ allTools.push(schema);
2636
+ }
2637
+ if (allTools.length > 0) {
2638
+ body["tools"] = allTools;
2639
+ }
2640
+ if (req.speed && req.speed !== "") {
2641
+ body["speed"] = req.speed;
2642
+ }
2643
+ if (req.outputConfig) {
2644
+ body["output_config"] = req.outputConfig;
2645
+ }
2646
+ const betas = buildBetas(caps, req);
2647
+ if (betas.length > 0) {
2648
+ body["betas"] = betas;
2649
+ }
2650
+ if (req.extraBody) {
2651
+ for (const [k, v] of Object.entries(req.extraBody)) {
2652
+ if (ANTHROPIC_SDK_MANAGED_BODY_KEYS.has(k)) {
2653
+ console.warn(
2654
+ `acosmi-sdk: extraBody key "${k}" is SDK-managed and was ignored (use the dedicated request field instead).`
2655
+ );
2656
+ continue;
2657
+ }
2658
+ body[k] = v;
2659
+ }
2660
+ }
2661
+ return body;
2662
+ }
2663
+ /**
2664
+ * 解析 Anthropic 格式同步响应
2665
+ * 兼容 APIResponse 包装 {"code":0,"data":{...}} 和裸 Anthropic JSON 两种格式
2666
+ */
2667
+ parseResponse(bodyInput) {
2668
+ const bodyStr = typeof bodyInput === "string" ? bodyInput : new TextDecoder().decode(bodyInput);
2669
+ let raw = bodyStr;
2670
+ try {
2671
+ const wrapper = JSON.parse(bodyStr);
2672
+ if (wrapper.data != null && wrapper.data !== null) {
2673
+ if ((wrapper.code ?? 0) !== 0) {
2674
+ throw new BusinessError(wrapper.code ?? 0, wrapper.message ?? "");
2675
+ }
2676
+ raw = JSON.stringify(wrapper.data);
2677
+ }
2678
+ } catch (e) {
2679
+ if (e instanceof BusinessError) throw e;
2680
+ }
2681
+ let resp;
2682
+ try {
2683
+ resp = JSON.parse(raw);
2684
+ } catch (e) {
2685
+ throw new Error(
2686
+ `decode anthropic response: ${e instanceof Error ? e.message : String(e)}`
2687
+ );
2688
+ }
2689
+ resp.tokenRemaining = -1;
2690
+ resp.callRemaining = -1;
2691
+ resp.modelTokenRemaining = -1;
2692
+ resp.modelTokenRemainingETU = -1;
2693
+ return resp;
2694
+ }
2695
+ /**
2696
+ * 解析 Anthropic SSE 行
2697
+ *
2698
+ * Anthropic 原生协议无 [DONE] (message_stop 后上游关闭连接),
2699
+ * 但 Nexus Gateway 的 ChatStream 路径会追加 [DONE] 哨兵, 此处一并处理。
2700
+ */
2701
+ parseStreamLine(eventType, data) {
2702
+ if (data === "[DONE]") {
2703
+ return { event: { event: "", data: "" }, done: true };
2704
+ }
2705
+ return { event: { event: eventType, data }, done: false };
2706
+ }
2707
+ };
2708
+ function resolveThinkingLevel(body, req, caps) {
2709
+ const level = req.thinking?.level ?? "";
2710
+ if (level === ThinkingOff) {
2711
+ body["thinking"] = { type: "disabled" };
2712
+ return;
2713
+ }
2714
+ if (!caps.supports_adaptive_thinking && !caps.supports_thinking) {
2715
+ return;
2716
+ }
2717
+ let maxTokens = req.max_tokens ?? 0;
2718
+ if (maxTokens <= 0) {
2719
+ maxTokens = ThinkingHighMinMaxTokens;
2720
+ }
2721
+ if (level === ThinkingMax) {
2722
+ let modelMax = caps.max_output_tokens;
2723
+ if (modelMax <= 0) modelMax = ThinkingMaxFallbackMaxTokens;
2724
+ if (maxTokens < modelMax) maxTokens = modelMax;
2725
+ } else {
2726
+ if (maxTokens < ThinkingHighMinMaxTokens) maxTokens = ThinkingHighMinMaxTokens;
2727
+ }
2728
+ body["max_tokens"] = maxTokens;
2729
+ if (caps.supports_adaptive_thinking) {
2730
+ const thinking = { type: "adaptive" };
2731
+ if (req.thinking?.display) thinking["display"] = req.thinking.display;
2732
+ body["thinking"] = thinking;
2733
+ } else if (caps.supports_thinking) {
2734
+ let budget = maxTokens - 1;
2735
+ if (budget < 1024) budget = 1024;
2736
+ const thinking = {
2737
+ type: "enabled",
2738
+ budget_tokens: budget
2739
+ };
2740
+ if (req.thinking?.display) thinking["display"] = req.thinking.display;
2741
+ body["thinking"] = thinking;
2742
+ }
2743
+ if (caps.supports_effort) {
2744
+ let effortLevel = "high";
2745
+ if (level === "low") effortLevel = "low";
2746
+ if (level === "medium" || level === "xhigh") effortLevel = level;
2747
+ if (level === ThinkingMax && caps.supports_max_effort) {
2748
+ effortLevel = "max";
2749
+ }
2750
+ body["effort"] = { level: effortLevel };
2751
+ }
2752
+ delete body["temperature"];
2753
+ }
2754
+
2755
+ // src/models/adapters/index.ts
2756
+ init_openai();
2757
+ init_format();
2758
+ init_openai();
2759
+ var adapterRegistry = {
2760
+ anthropic: new AnthropicAdapter(),
2761
+ /** Acosmi 自有模型走 Anthropic 格式 */
2762
+ acosmi: new AnthropicAdapter()
2763
+ };
2764
+ var defaultOpenAIAdapter = new OpenAIAdapter();
2765
+ function getAdapter(provider) {
2766
+ const a = adapterRegistry[provider.toLowerCase()];
2767
+ if (a) return a;
2768
+ return defaultOpenAIAdapter;
2769
+ }
2770
+ function getAdapterForModel(m) {
2771
+ let hasAnthropic = false;
2772
+ let hasOpenAI = false;
2773
+ for (const f of m.supported_formats ?? []) {
2774
+ switch (f.trim().toLowerCase()) {
2775
+ case "anthropic":
2776
+ hasAnthropic = true;
2777
+ break;
2778
+ case "openai":
2779
+ hasOpenAI = true;
2780
+ break;
2781
+ }
2782
+ }
2783
+ const declared = hasAnthropic || hasOpenAI;
2784
+ const pref = (m.preferred_format ?? "").trim().toLowerCase();
2785
+ switch (pref) {
2786
+ case "anthropic":
2787
+ if (!declared || hasAnthropic) return new AnthropicAdapter();
2788
+ break;
2789
+ case "openai":
2790
+ if (!declared || hasOpenAI) return new OpenAIAdapter();
2791
+ break;
2792
+ }
2793
+ if (hasAnthropic) return new AnthropicAdapter();
2794
+ if (hasOpenAI) return new OpenAIAdapter();
2795
+ return getAdapter((m.provider ?? "").toLowerCase());
2796
+ }
2677
2797
 
2678
2798
  // src/models/stream-meta.ts
2679
2799
  function extractAnthropicBlockMeta(eventType, data, blockTypeMap) {
@@ -2860,7 +2980,7 @@ function parseStreamError(data) {
2860
2980
  let code = payload.errorCode ?? "";
2861
2981
  const stage = payload.stage ?? "";
2862
2982
  let message = payload.message ?? "";
2863
- const retryable = payload.retryable ?? false;
2983
+ const retryable = payload.retryable;
2864
2984
  let rawError = "";
2865
2985
  if (payload.error != null) {
2866
2986
  if (typeof payload.error === "string") {
@@ -2878,6 +2998,7 @@ function parseStreamError(data) {
2878
2998
  message,
2879
2999
  rawError,
2880
3000
  retryable,
3001
+ retryAfterSecs: payload.retryAfterSecs,
2881
3002
  errorContractVersion: payload.errorContractVersion,
2882
3003
  faultDomain: payload.faultDomain,
2883
3004
  requestDisposition: payload.requestDisposition,
@@ -3088,6 +3209,25 @@ function notifyGatewayRequestID(cb, headers) {
3088
3209
  } catch {
3089
3210
  }
3090
3211
  }
3212
+ function notifyResponseHeaders(cb, headers) {
3213
+ if (!cb) return;
3214
+ try {
3215
+ cb(headers);
3216
+ } catch {
3217
+ }
3218
+ }
3219
+ function armStreamRequestTimeout(opts, parent) {
3220
+ const ms = opts?.requestTimeoutMs;
3221
+ if (typeof ms !== "number" || !Number.isFinite(ms) || ms <= 0) return void 0;
3222
+ return withRequestTimeout(ms, parent);
3223
+ }
3224
+ async function* disposeTimeoutWhenSettled(inner, ctl) {
3225
+ try {
3226
+ yield* inner;
3227
+ } finally {
3228
+ ctl.dispose();
3229
+ }
3230
+ }
3091
3231
  var DEFAULT_API_TIMEOUT_MS = 6e4;
3092
3232
  function newDeferred() {
3093
3233
  let resolve;
@@ -4221,10 +4361,23 @@ var Client = class _Client {
4221
4361
  *
4222
4362
  * @param onUpstreamActivity 见 {@link UpstreamActivityCallback}
4223
4363
  * @param onGatewayRequestID 见 {@link GatewayRequestIDCallback}
4364
+ * @param opts 见 {@link ChatStreamOptions} (2.19.5 起)
4224
4365
  */
4225
- chatStream(modelID, req, signal, onUpstreamActivity, onGatewayRequestID) {
4366
+ chatStream(modelID, req, signal, onUpstreamActivity, onGatewayRequestID, opts) {
4226
4367
  return {
4227
- [Symbol.asyncIterator]: () => this.chatStreamGen(modelID, req, signal, false, onUpstreamActivity, onGatewayRequestID)
4368
+ [Symbol.asyncIterator]: () => {
4369
+ const ctl = armStreamRequestTimeout(opts, signal);
4370
+ const inner = this.chatStreamGen(
4371
+ modelID,
4372
+ req,
4373
+ ctl?.signal ?? signal,
4374
+ false,
4375
+ onUpstreamActivity,
4376
+ onGatewayRequestID,
4377
+ opts?.onResponseHeaders
4378
+ );
4379
+ return ctl ? disposeTimeoutWhenSettled(inner, ctl) : inner;
4380
+ }
4228
4381
  };
4229
4382
  }
4230
4383
  /**
@@ -4234,13 +4387,26 @@ var Client = class _Client {
4234
4387
  *
4235
4388
  * @param onUpstreamActivity 见 {@link UpstreamActivityCallback}
4236
4389
  * @param onGatewayRequestID 见 {@link GatewayRequestIDCallback}
4390
+ * @param opts 见 {@link ChatStreamOptions} (2.19.5 起)
4237
4391
  */
4238
- chatMessagesStream(modelID, req, signal, onUpstreamActivity, onGatewayRequestID) {
4392
+ chatMessagesStream(modelID, req, signal, onUpstreamActivity, onGatewayRequestID, opts) {
4239
4393
  return {
4240
- [Symbol.asyncIterator]: () => this.chatMessagesStreamGen(modelID, req, signal, false, onUpstreamActivity, onGatewayRequestID)
4394
+ [Symbol.asyncIterator]: () => {
4395
+ const ctl = armStreamRequestTimeout(opts, signal);
4396
+ const inner = this.chatMessagesStreamGen(
4397
+ modelID,
4398
+ req,
4399
+ ctl?.signal ?? signal,
4400
+ false,
4401
+ onUpstreamActivity,
4402
+ onGatewayRequestID,
4403
+ opts?.onResponseHeaders
4404
+ );
4405
+ return ctl ? disposeTimeoutWhenSettled(inner, ctl) : inner;
4406
+ }
4241
4407
  };
4242
4408
  }
4243
- async *chatStreamGen(modelID, req, signal, retried, onUpstreamActivity, onGatewayRequestID) {
4409
+ async *chatStreamGen(modelID, req, signal, retried, onUpstreamActivity, onGatewayRequestID, onResponseHeaders) {
4244
4410
  const r = { ...req, stream: true };
4245
4411
  const { body, adapter } = await this.buildChatRequest(modelID, r, signal);
4246
4412
  const token = await this.ensureToken(signal);
@@ -4272,10 +4438,11 @@ var Client = class _Client {
4272
4438
  `stream: unauthorized and refresh failed: ${refreshErr instanceof Error ? refreshErr.message : String(refreshErr)}`
4273
4439
  );
4274
4440
  }
4275
- yield* this.chatStreamGen(modelID, req, signal, true, onUpstreamActivity, onGatewayRequestID);
4441
+ yield* this.chatStreamGen(modelID, req, signal, true, onUpstreamActivity, onGatewayRequestID, onResponseHeaders);
4276
4442
  return;
4277
4443
  }
4278
4444
  notifyGatewayRequestID(onGatewayRequestID, resp.headers);
4445
+ notifyResponseHeaders(onResponseHeaders, resp.headers);
4279
4446
  if (!resp.ok) {
4280
4447
  const bodyBytes = await readLimited(resp.body, maxErrorBodySize);
4281
4448
  throw parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers);
@@ -4310,7 +4477,7 @@ var Client = class _Client {
4310
4477
  }
4311
4478
  }
4312
4479
  }
4313
- async *chatMessagesStreamGen(modelID, req, signal, retried, onUpstreamActivity, onGatewayRequestID) {
4480
+ async *chatMessagesStreamGen(modelID, req, signal, retried, onUpstreamActivity, onGatewayRequestID, onResponseHeaders) {
4314
4481
  const r = { ...req, stream: true };
4315
4482
  const { body, adapter } = await this.buildChatRequest(modelID, r, signal);
4316
4483
  const token = await this.ensureToken(signal);
@@ -4342,10 +4509,11 @@ var Client = class _Client {
4342
4509
  `messages stream: unauthorized and refresh failed: ${refreshErr instanceof Error ? refreshErr.message : String(refreshErr)}`
4343
4510
  );
4344
4511
  }
4345
- yield* this.chatMessagesStreamGen(modelID, req, signal, true, onUpstreamActivity, onGatewayRequestID);
4512
+ yield* this.chatMessagesStreamGen(modelID, req, signal, true, onUpstreamActivity, onGatewayRequestID, onResponseHeaders);
4346
4513
  return;
4347
4514
  }
4348
4515
  notifyGatewayRequestID(onGatewayRequestID, resp.headers);
4516
+ notifyResponseHeaders(onResponseHeaders, resp.headers);
4349
4517
  if (!resp.ok) {
4350
4518
  const bodyBytes = await readLimited(resp.body, maxErrorBodySize);
4351
4519
  throw parseHTTPErrorWithHeader(resp.status, bodyBytes, resp.headers);
@@ -4371,6 +4539,7 @@ var Client = class _Client {
4371
4539
  if (done) return;
4372
4540
  }
4373
4541
  }
4542
+ for (const ev of converter.flush()) yield ev;
4374
4543
  } else {
4375
4544
  const blockTypeMap = /* @__PURE__ */ new Map();
4376
4545
  let currentEvent = "";
@@ -5288,10 +5457,6 @@ function findDesktopVisualUnderstandingModel(models) {
5288
5457
  return candidates[0];
5289
5458
  }
5290
5459
 
5291
- // src/models/index.ts
5292
- init_adapters();
5293
- init_betas();
5294
-
5295
5460
  // src/billing/entitlements.ts
5296
5461
  Client.prototype.getBalance = async function(signal) {
5297
5462
  const resp = await this.doJSON(
@@ -8884,6 +9049,6 @@ function brandCredential(c) {
8884
9049
  return c;
8885
9050
  }
8886
9051
 
8887
- 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, 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, ThinkingLow, 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, isUserAccessTokenRejected, isValidTokenSet, isWindowLimitError, isWindowLimitStreamError, maxEndUserIdLength, modelScopes, modelSupportsImageInput, modelSupportsInputModality, newFileTokenStore, newThinkingConfig, newTokenSet, newWebSearchTool, normalizeGatewayBaseURL, normalizeOverrideBaseURL, parseNotificationEvent, parseRemoteControlEvent, parseSettlement, parseSourcesEvent, readGatewayErrorContract, refreshToken, register, registerWebOAuthClient, remoteControlScopes, retryReasonForComplianceKey, retryReasonForOAuthError, revokeToken, sanitize_exports as sanitize, skillScopes, tokenSetIsExpired, uniqueMerge, validateEndUserId };
9052
+ 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, 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, ThinkingLow, 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, isStreamError, isTerminalRemoteEvent, isUserAccessTokenRejected, isValidTokenSet, isWindowLimitError, isWindowLimitStreamError, maxEndUserIdLength, modelScopes, modelSupportsImageInput, modelSupportsInputModality, newFileTokenStore, newThinkingConfig, newTokenSet, newWebSearchTool, normalizeGatewayBaseURL, normalizeOverrideBaseURL, parseNotificationEvent, parseRemoteControlEvent, parseSettlement, parseSourcesEvent, readGatewayErrorContract, refreshToken, register, registerWebOAuthClient, remoteControlScopes, retryReasonForComplianceKey, retryReasonForOAuthError, revokeToken, sanitize_exports as sanitize, skillScopes, tokenSetIsExpired, uniqueMerge, validateEndUserId };
8888
9053
  //# sourceMappingURL=index.mjs.map
8889
9054
  //# sourceMappingURL=index.mjs.map