@rulvar/openai 1.73.0 → 1.75.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.
Files changed (2) hide show
  1. package/dist/index.js +57 -7
  2. package/package.json +3 -3
package/dist/index.js CHANGED
@@ -16,6 +16,7 @@ function responses(contextWindow, maxOutputTokens, pricing, options) {
16
16
  reasoningEfforts: [...REASONING_EFFORTS, "max"],
17
17
  contextWindow,
18
18
  maxOutputTokens,
19
+ minOutputTokensPerTurn: 16,
19
20
  ...pricing === void 0 ? {} : { pricing }
20
21
  },
21
22
  api: "responses",
@@ -236,7 +237,7 @@ function buildResponsesParams(req, ids, options) {
236
237
  type: "function_call",
237
238
  call_id: ids.wireFor(part.id),
238
239
  name: part.name,
239
- arguments: JSON.stringify(part.args ?? {})
240
+ arguments: argumentsTextOf(part.args)
240
241
  });
241
242
  break;
242
243
  case "tool-result":
@@ -557,18 +558,65 @@ function retryAfterMsFrom(header) {
557
558
  if (match === null) return;
558
559
  return Math.min(Number(match[1]) * 1e3, MAX_RETRY_AFTER_MS);
559
560
  }
561
+ /**
562
+ * A plain nonnegative SAFE integer header value, or undefined. The
563
+ * digit-run grammar alone still admits an arbitrarily long run, and
564
+ * Number() turns 400 digits into Infinity (the v1.74 experiment
565
+ * review, P2.11): an unsafe value is dropped, never normalized.
566
+ */
567
+ function limitHeaderValue(header) {
568
+ if (header === void 0) return;
569
+ const match = /^[\t ]*([0-9]+)[\t ]*$/.exec(header);
570
+ if (match === null) return;
571
+ const value = Number(match[1]);
572
+ return Number.isSafeInteger(value) ? value : void 0;
573
+ }
574
+ /**
575
+ * Serializes tool-call arguments for re-projection into the request. An
576
+ * adapter parse-failure wrapper ({__unparsed: raw} and nothing else)
577
+ * projects as the ORIGINAL raw string the model wrote (the v1.74
578
+ * experiment review): re-encoding the internal wrapper showed the live
579
+ * model {"__unparsed":"..."} as its own past call, taught it to imitate
580
+ * that shape, and doubled the history bytes with escaping.
581
+ */
582
+ function argumentsTextOf(args) {
583
+ if (typeof args === "object" && args !== null && !Array.isArray(args)) {
584
+ const keys = Object.keys(args);
585
+ const raw = args.__unparsed;
586
+ if (keys.length === 1 && keys[0] === "__unparsed" && typeof raw === "string") return raw;
587
+ }
588
+ return JSON.stringify(args ?? {});
589
+ }
560
590
  /** Projects SDK/API errors into the retryable WireError vocabulary. */
561
591
  function openAiErrorToWire(error) {
562
592
  const record = error;
563
593
  const status = typeof record.status === "number" ? record.status : void 0;
564
594
  const message = typeof record.message === "string" ? record.message : String(error);
565
- if (status === 429) {
566
- let retryAfterMs;
595
+ const headerGet = (name) => {
567
596
  const headers = record.headers;
568
- if (headers !== void 0 && headers !== null) {
569
- const value = typeof headers.get === "function" ? headers.get("retry-after") ?? void 0 : headers["retry-after"];
570
- if (value !== void 0) retryAfterMs = retryAfterMsFrom(value);
597
+ if (headers === void 0 || headers === null) return;
598
+ if (typeof headers.get === "function") return headers.get(name) ?? void 0;
599
+ return headers[name];
600
+ };
601
+ if (status === 429) {
602
+ const retryAfterHeader = headerGet("retry-after");
603
+ const retryAfterMs = retryAfterHeader === void 0 ? void 0 : retryAfterMsFrom(retryAfterHeader);
604
+ const buckets = {};
605
+ for (const name of [
606
+ "x-ratelimit-limit-requests",
607
+ "x-ratelimit-remaining-requests",
608
+ "x-ratelimit-limit-tokens",
609
+ "x-ratelimit-remaining-tokens"
610
+ ]) {
611
+ const value = headerGet(name);
612
+ if (value !== void 0) buckets[name] = value;
571
613
  }
614
+ const requestsPerMinute = limitHeaderValue(headerGet("x-ratelimit-limit-requests"));
615
+ const tokensPerMinute = limitHeaderValue(headerGet("x-ratelimit-limit-tokens"));
616
+ const reportedLimits = {
617
+ ...requestsPerMinute === void 0 ? {} : { requestsPerMinute },
618
+ ...tokensPerMinute === void 0 ? {} : { tokensPerMinute }
619
+ };
572
620
  return {
573
621
  code: "agent",
574
622
  message,
@@ -576,6 +624,8 @@ function openAiErrorToWire(error) {
576
624
  data: {
577
625
  kind: "rate-limit",
578
626
  ...retryAfterMs === void 0 ? {} : { retryAfterMs },
627
+ ...Object.keys(buckets).length > 0 ? { buckets } : {},
628
+ ...Object.keys(reportedLimits).length > 0 ? { reportedLimits } : {},
579
629
  status: 429
580
630
  }
581
631
  };
@@ -617,7 +667,7 @@ function buildChatCompletionsParams(req, ids) {
617
667
  type: "function",
618
668
  function: {
619
669
  name: call.name,
620
- arguments: JSON.stringify(call.args ?? {})
670
+ arguments: argumentsTextOf(call.args)
621
671
  }
622
672
  };
623
673
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rulvar/openai",
3
- "version": "1.73.0",
3
+ "version": "1.75.0",
4
4
  "description": "Rulvar first-class provider adapter for the OpenAI Responses API, plus the openaiCompatible factory.",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -23,13 +23,13 @@
23
23
  },
24
24
  "dependencies": {
25
25
  "openai": "^6.45.0",
26
- "@rulvar/core": "1.73.0"
26
+ "@rulvar/core": "1.75.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.73.0"
32
+ "@rulvar/testing": "1.75.0"
33
33
  },
34
34
  "repository": {
35
35
  "type": "git",