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