@rulvar/openai 1.16.2 → 1.18.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
@@ -7,6 +7,14 @@ interface OpenAiModelInfo {
7
7
  api: "responses" | "chat";
8
8
  /** Reasoning models reject non-default sampling parameters. */
9
9
  reasoning: boolean;
10
+ /**
11
+ * The model accepts wire `reasoning.effort: "max"` (GPT-5.6 Sol per
12
+ * the official model docs). When false, canonical max downmaps to
13
+ * wire xhigh; the downmap is recorded in providerMetadata and the
14
+ * journal identity keeps max, so caps accept the full canonical set
15
+ * either way.
16
+ */
17
+ wireMaxEffort: boolean;
10
18
  }
11
19
  /** Static seed table of the current model set. */
12
20
  declare const OPENAI_MODELS: Record<string, OpenAiModelInfo>;
@@ -111,12 +119,15 @@ declare class OpenAiIdMap {
111
119
  wireFor(canonicalId: CanonicalId): string;
112
120
  }
113
121
  /**
114
- * Canonical-to-wire effort: low through
115
- * xhigh pass through; canonical max downmaps to xhigh (documented lossy;
116
- * recorded in providerMetadata); provider 'none' is reachable only via
117
- * providerOptions.openai.reasoningEffort.
122
+ * Canonical-to-wire effort: low through xhigh pass through. Canonical
123
+ * max passes through unchanged on models whose caps declare wire max
124
+ * support (GPT-5.6 Sol); elsewhere it downmaps to xhigh (documented
125
+ * lossy; recorded in providerMetadata). Provider 'none' is reachable
126
+ * only via providerOptions.openai.reasoningEffort.
118
127
  */
119
- declare function mapOpenAiEffort(effort: Effort): {
128
+ declare function mapOpenAiEffort(effort: Effort, options?: {
129
+ wireMaxEffort?: boolean;
130
+ }): {
120
131
  wire: string;
121
132
  downmapped: boolean;
122
133
  };
@@ -127,7 +138,9 @@ declare function mapOpenAiEffort(effort: Effort): {
127
138
  * are REJECTED as a typed ConfigError. Role
128
139
  * 'system' messages project into top-level instructions on every request.
129
140
  */
130
- declare function buildResponsesParams(req: ChatRequest, ids: OpenAiIdMap): {
141
+ declare function buildResponsesParams(req: ChatRequest, ids: OpenAiIdMap, options?: {
142
+ wireMaxEffort?: boolean;
143
+ }): {
131
144
  params: Record<string, unknown>;
132
145
  effortDownmapped: boolean;
133
146
  };
package/dist/index.js CHANGED
@@ -7,7 +7,7 @@ const REASONING_EFFORTS = [
7
7
  "high",
8
8
  "xhigh"
9
9
  ];
10
- function responses(contextWindow, maxOutputTokens, pricing) {
10
+ function responses(contextWindow, maxOutputTokens, pricing, options) {
11
11
  return {
12
12
  caps: {
13
13
  structuredOutput: "native",
@@ -19,28 +19,47 @@ function responses(contextWindow, maxOutputTokens, pricing) {
19
19
  ...pricing === void 0 ? {} : { pricing }
20
20
  },
21
21
  api: "responses",
22
- reasoning: true
22
+ reasoning: true,
23
+ wireMaxEffort: options?.wireMaxEffort === true
23
24
  };
24
25
  }
26
+ const GPT_56_TIERS = [{
27
+ aboveInputTokens: 272e3,
28
+ inputMultiplier: 2,
29
+ outputMultiplier: 1.5
30
+ }];
25
31
  /**
26
- * GPT-5.6 Sol (developers.openai.com/api/docs/models/gpt-5.6-sol):
27
- * prompts strictly above 272K input tokens price the FULL request at
28
- * 2x input and 1.5x output; cache writes bill at 1.25x uncached input.
32
+ * GPT-5.6 Sol, Terra, and Luna are three sibling models, not snapshots
33
+ * of one model (developers.openai.com/api/docs/models/gpt-5.6-sol,
34
+ * .../gpt-5.6-terra, .../gpt-5.6-luna; rates verified 2026-07-18). All
35
+ * three: prompts strictly above 272K input tokens price the FULL
36
+ * request at 2x input and 1.5x output; cache writes bill at 1.25x
37
+ * uncached input. Only Sol accepts wire reasoning effort `max`.
29
38
  */
30
39
  const GPT_56_SOL = responses(105e4, 128e3, {
31
40
  inputUsdPerMTok: 5,
32
41
  outputUsdPerMTok: 30,
33
42
  cacheReadUsdPerMTok: .5,
34
43
  cacheWriteUsdPerMTok: 6.25,
35
- tiers: [{
36
- aboveInputTokens: 272e3,
37
- inputMultiplier: 2,
38
- outputMultiplier: 1.5
39
- }]
40
- });
44
+ tiers: GPT_56_TIERS
45
+ }, { wireMaxEffort: true });
41
46
  /** Static seed table of the current model set. */
42
47
  const OPENAI_MODELS = {
43
48
  "gpt-5.6-sol": GPT_56_SOL,
49
+ "gpt-5.6-terra": responses(105e4, 128e3, {
50
+ inputUsdPerMTok: 2.5,
51
+ outputUsdPerMTok: 15,
52
+ cacheReadUsdPerMTok: .25,
53
+ cacheWriteUsdPerMTok: 3.125,
54
+ tiers: GPT_56_TIERS
55
+ }),
56
+ "gpt-5.6-luna": responses(105e4, 128e3, {
57
+ inputUsdPerMTok: 1,
58
+ outputUsdPerMTok: 6,
59
+ cacheReadUsdPerMTok: .1,
60
+ cacheWriteUsdPerMTok: 1.25,
61
+ tiers: GPT_56_TIERS
62
+ }),
44
63
  "gpt-5.6": GPT_56_SOL,
45
64
  "gpt-5.5": responses(4e5, 128e3, {
46
65
  inputUsdPerMTok: 10,
@@ -83,22 +102,30 @@ const OPENAI_MODELS = {
83
102
  * silent reinterpretation.
84
103
  */
85
104
  const OPENAI_PRICING = {
86
- pricingVersion: "openai-2026-07-16",
105
+ pricingVersion: "openai-2026-07-18",
87
106
  models: (() => {
88
107
  const models = {};
89
108
  for (const [name, info] of Object.entries(OPENAI_MODELS)) if (info.caps.pricing !== void 0) models[`openai:${name}`] = info.caps.pricing;
90
109
  return models;
91
110
  })()
92
111
  };
112
+ /**
113
+ * The documented snapshot grammar: `<exact model>-YYYY-MM-DD`. Nothing
114
+ * else inherits a table row (v1.17.0 review P1-1): a general prefix
115
+ * matcher let the 'gpt-5.6' family alias capture the SIBLING models
116
+ * 'gpt-5.6-terra' and 'gpt-5.6-luna' and price them as Sol, which is
117
+ * worse than no price at all. An unknown sibling or preview suffix now
118
+ * falls through to conservative unpriced caps.
119
+ */
120
+ const DATED_SNAPSHOT = /^(?<base>.+)-\d{4}-\d{2}-\d{2}$/u;
93
121
  function openAiModelInfo(model) {
94
122
  const exact = OPENAI_MODELS[model];
95
123
  if (exact !== void 0) return exact;
96
- let best;
97
- for (const [name, info] of Object.entries(OPENAI_MODELS)) if (model.startsWith(`${name}-`) && (best === void 0 || name.length > best.name.length)) best = {
98
- name,
99
- info
100
- };
101
- if (best !== void 0) return best.info;
124
+ const snapshot = DATED_SNAPSHOT.exec(model)?.groups?.base;
125
+ if (snapshot !== void 0) {
126
+ const base = OPENAI_MODELS[snapshot];
127
+ if (base !== void 0) return base;
128
+ }
102
129
  return responses(272e3, 1e5);
103
130
  }
104
131
  //#endregion
@@ -140,13 +167,14 @@ var OpenAiIdMap = class {
140
167
  }
141
168
  };
142
169
  /**
143
- * Canonical-to-wire effort: low through
144
- * xhigh pass through; canonical max downmaps to xhigh (documented lossy;
145
- * recorded in providerMetadata); provider 'none' is reachable only via
146
- * providerOptions.openai.reasoningEffort.
170
+ * Canonical-to-wire effort: low through xhigh pass through. Canonical
171
+ * max passes through unchanged on models whose caps declare wire max
172
+ * support (GPT-5.6 Sol); elsewhere it downmaps to xhigh (documented
173
+ * lossy; recorded in providerMetadata). Provider 'none' is reachable
174
+ * only via providerOptions.openai.reasoningEffort.
147
175
  */
148
- function mapOpenAiEffort(effort) {
149
- if (effort === "max") return {
176
+ function mapOpenAiEffort(effort, options) {
177
+ if (effort === "max" && options?.wireMaxEffort !== true) return {
150
178
  wire: "xhigh",
151
179
  downmapped: true
152
180
  };
@@ -162,7 +190,7 @@ function mapOpenAiEffort(effort) {
162
190
  * are REJECTED as a typed ConfigError. Role
163
191
  * 'system' messages project into top-level instructions on every request.
164
192
  */
165
- function buildResponsesParams(req, ids) {
193
+ function buildResponsesParams(req, ids, options) {
166
194
  const openaiOptions = req.providerOptions?.openai ?? {};
167
195
  for (const forbidden of [
168
196
  "previous_response_id",
@@ -260,7 +288,7 @@ function buildResponsesParams(req, ids) {
260
288
  const explicitEffort = openaiOptions.reasoningEffort;
261
289
  if (typeof explicitEffort === "string") params.reasoning = { effort: explicitEffort };
262
290
  else if (req.effort !== void 0) {
263
- const mapped = mapOpenAiEffort(req.effort);
291
+ const mapped = mapOpenAiEffort(req.effort, options);
264
292
  effortDownmapped = mapped.downmapped;
265
293
  params.reasoning = { effort: mapped.wire };
266
294
  }
@@ -655,7 +683,7 @@ function openai(options = {}) {
655
683
  const info = openAiModelInfo(req.model);
656
684
  try {
657
685
  if (info.api === "responses") {
658
- const { params, effortDownmapped } = buildResponsesParams(req, ids);
686
+ const { params, effortDownmapped } = buildResponsesParams(req, ids, { wireMaxEffort: info.wireMaxEffort });
659
687
  yield* mapResponsesStream(await client.responses.create({
660
688
  ...params,
661
689
  stream: true
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rulvar/openai",
3
- "version": "1.16.2",
3
+ "version": "1.18.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.16.2"
26
+ "@rulvar/core": "1.18.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.16.2"
32
+ "@rulvar/testing": "1.18.0"
33
33
  },
34
34
  "repository": {
35
35
  "type": "git",