@rulvar/anthropic 1.28.0 → 1.30.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -165,8 +165,14 @@ interface TurnMapping {
165
165
  * detached work). The generator's RETURN value carries the accumulated
166
166
  * turn state the adapter needs for pause_turn continuation. Yields an
167
167
  * early usage event from message_start (the input side is known
168
- * immediately) and exactly one terminal finish unless the turn paused
169
- * (pause_turn) or errored. `carryRetained` holds thinking blocks from
168
+ * immediately) and exactly one terminal finish when the stream reaches
169
+ * message_stop. A stream that pauses (pause_turn) or ends before
170
+ * message_stop yields NO terminal event of its own: the return value's
171
+ * pauseTurn and finished flags report which case happened, and the
172
+ * `anthropic()` adapter turns a truncated read (finished false without
173
+ * a pause) into the retryable transport error the contract requires,
174
+ * so a direct mapper consumer must check the flags rather than wait
175
+ * for an error event. `carryRetained` holds thinking blocks from
170
176
  * earlier pause_turn continuations of the same turn so the terminal
171
177
  * finish ships the whole turn's retention payload (M4-T02).
172
178
  */
package/dist/index.js CHANGED
@@ -442,8 +442,14 @@ function normalizeAnthropicUsage(raw) {
442
442
  * detached work). The generator's RETURN value carries the accumulated
443
443
  * turn state the adapter needs for pause_turn continuation. Yields an
444
444
  * early usage event from message_start (the input side is known
445
- * immediately) and exactly one terminal finish unless the turn paused
446
- * (pause_turn) or errored. `carryRetained` holds thinking blocks from
445
+ * immediately) and exactly one terminal finish when the stream reaches
446
+ * message_stop. A stream that pauses (pause_turn) or ends before
447
+ * message_stop yields NO terminal event of its own: the return value's
448
+ * pauseTurn and finished flags report which case happened, and the
449
+ * `anthropic()` adapter turns a truncated read (finished false without
450
+ * a pause) into the retryable transport error the contract requires,
451
+ * so a direct mapper consumer must check the flags rather than wait
452
+ * for an error event. `carryRetained` holds thinking blocks from
447
453
  * earlier pause_turn continuations of the same turn so the terminal
448
454
  * finish ships the whole turn's retention payload (M4-T02).
449
455
  */
@@ -603,6 +609,25 @@ async function* mapAnthropicStream(stream, ids, options) {
603
609
  return mapping;
604
610
  }
605
611
  /**
612
+ * Largest delay a Node timer represents exactly; a bigger value would
613
+ * overflow into an almost immediate (storm inducing) retry.
614
+ */
615
+ const MAX_RETRY_AFTER_MS = 2147483647;
616
+ /**
617
+ * Parses a Retry-After header into milliseconds. Only the RFC delta
618
+ * seconds grammar is honored: after trimming optional whitespace the
619
+ * value must be a nonempty run of decimal digits, so the HTTP date
620
+ * form, signs, decimals, hex, exponents, and empty values all return
621
+ * undefined and the engine falls back to its computed policy backoff
622
+ * (v1.29.0 review P3; `Number()` alone accepted every one of those).
623
+ * A huge digit run is clamped to the Node timer maximum.
624
+ */
625
+ function retryAfterMsFrom(header) {
626
+ const trimmed = header.trim();
627
+ if (!/^[0-9]+$/.test(trimmed)) return;
628
+ return Math.min(Number(trimmed) * 1e3, MAX_RETRY_AFTER_MS);
629
+ }
630
+ /**
606
631
  * Projects an SDK/API error into the retryable WireError vocabulary:
607
632
  * 429 rate limits surface retryAfterMs and the x-ratelimit-* buckets; 529
608
633
  * overloaded and 5xx are retryable transport; everything else is terminal
@@ -619,7 +644,8 @@ function anthropicErrorToWire(error) {
619
644
  return headers[name];
620
645
  };
621
646
  if (status === 429) {
622
- const retryAfter = headerGet("retry-after");
647
+ const retryAfterHeader = headerGet("retry-after");
648
+ const retryAfterMs = retryAfterHeader === void 0 ? void 0 : retryAfterMsFrom(retryAfterHeader);
623
649
  const buckets = {};
624
650
  for (const name of [
625
651
  "x-ratelimit-limit-requests",
@@ -638,7 +664,7 @@ function anthropicErrorToWire(error) {
638
664
  retryable: true,
639
665
  data: {
640
666
  kind: "rate-limit",
641
- ...retryAfter === void 0 ? {} : { retryAfterMs: Number(retryAfter) * 1e3 },
667
+ ...retryAfterMs === void 0 ? {} : { retryAfterMs },
642
668
  ...Object.keys(buckets).length > 0 ? { buckets } : {},
643
669
  status: 429
644
670
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rulvar/anthropic",
3
- "version": "1.28.0",
3
+ "version": "1.30.0",
4
4
  "description": "Rulvar first-class provider adapter over @anthropic-ai/sdk.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -23,13 +23,13 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "@anthropic-ai/sdk": "^0.110.0",
26
- "@rulvar/core": "1.28.0"
26
+ "@rulvar/core": "1.30.0"
27
27
  },
28
28
  "devDependencies": {
29
29
  "@types/node": "^22.20.0",
30
30
  "tsdown": "^0.22.3",
31
31
  "typescript": "~6.0.3",
32
- "@rulvar/testing": "1.28.0"
32
+ "@rulvar/testing": "1.30.0"
33
33
  },
34
34
  "repository": {
35
35
  "type": "git",