@bastani/pi-ai 0.9.24 → 0.9.25-alpha.1

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 (100) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/NOTICE.md +1 -1
  3. package/README.md +17 -6
  4. package/dist/api/cloudflare-workers-ai-system-one.js +2 -2
  5. package/dist/api/cloudflare-workers-ai-system-one.js.map +1 -1
  6. package/dist/api/openai-codex-responses.d.ts +2 -2
  7. package/dist/api/openai-codex-responses.d.ts.map +1 -1
  8. package/dist/api/openai-codex-responses.js +8 -28
  9. package/dist/api/openai-codex-responses.js.map +1 -1
  10. package/dist/api/openai-responses-shared.d.ts +25 -6
  11. package/dist/api/openai-responses-shared.d.ts.map +1 -1
  12. package/dist/api/openai-responses-shared.js +66 -19
  13. package/dist/api/openai-responses-shared.js.map +1 -1
  14. package/dist/api/openai-responses.d.ts +2 -1
  15. package/dist/api/openai-responses.d.ts.map +1 -1
  16. package/dist/api/openai-responses.js +21 -32
  17. package/dist/api/openai-responses.js.map +1 -1
  18. package/dist/api/system-one-shared.d.ts +2 -2
  19. package/dist/api/system-one-shared.d.ts.map +1 -1
  20. package/dist/api/system-one-shared.js +26 -1
  21. package/dist/api/system-one-shared.js.map +1 -1
  22. package/dist/api/typesafe-system-one.js +2 -2
  23. package/dist/api/typesafe-system-one.js.map +1 -1
  24. package/dist/auth/helpers.js +1 -1
  25. package/dist/auth/helpers.js.map +1 -1
  26. package/dist/auth/oauth/anthropic.d.ts.map +1 -1
  27. package/dist/auth/oauth/anthropic.js +19 -128
  28. package/dist/auth/oauth/anthropic.js.map +1 -1
  29. package/dist/auth/oauth/callback-server.d.ts +31 -0
  30. package/dist/auth/oauth/callback-server.d.ts.map +1 -0
  31. package/dist/auth/oauth/callback-server.js +138 -0
  32. package/dist/auth/oauth/callback-server.js.map +1 -0
  33. package/dist/auth/oauth/load.d.ts +2 -0
  34. package/dist/auth/oauth/load.d.ts.map +1 -1
  35. package/dist/auth/oauth/load.js +5 -0
  36. package/dist/auth/oauth/load.js.map +1 -1
  37. package/dist/auth/oauth/oauth-page.js +1 -1
  38. package/dist/auth/oauth/oauth-page.js.map +1 -1
  39. package/dist/auth/oauth/openai-chatgpt.d.ts +3 -0
  40. package/dist/auth/oauth/openai-chatgpt.d.ts.map +1 -0
  41. package/dist/auth/oauth/openai-chatgpt.js +250 -0
  42. package/dist/auth/oauth/openai-chatgpt.js.map +1 -0
  43. package/dist/auth/oauth/openai-codex.d.ts +1 -1
  44. package/dist/auth/oauth/openai-codex.d.ts.map +1 -1
  45. package/dist/auth/oauth/openai-codex.js +20 -124
  46. package/dist/auth/oauth/openai-codex.js.map +1 -1
  47. package/dist/auth/oauth/openrouter.d.ts +1 -1
  48. package/dist/auth/oauth/openrouter.d.ts.map +1 -1
  49. package/dist/auth/oauth/openrouter.js +19 -138
  50. package/dist/auth/oauth/openrouter.js.map +1 -1
  51. package/dist/auth/oauth/radius.d.ts +1 -1
  52. package/dist/auth/oauth/radius.d.ts.map +1 -1
  53. package/dist/auth/oauth/radius.js +21 -89
  54. package/dist/auth/oauth/radius.js.map +1 -1
  55. package/dist/auth/types.d.ts +6 -1
  56. package/dist/auth/types.d.ts.map +1 -1
  57. package/dist/auth/types.js.map +1 -1
  58. package/dist/bun-oauth.d.ts.map +1 -1
  59. package/dist/bun-oauth.js +2 -0
  60. package/dist/bun-oauth.js.map +1 -1
  61. package/dist/cli.js +2 -1
  62. package/dist/cli.js.map +1 -1
  63. package/dist/models.d.ts +5 -3
  64. package/dist/models.d.ts.map +1 -1
  65. package/dist/models.js +6 -2
  66. package/dist/models.js.map +1 -1
  67. package/dist/providers/data/.manifest.json +1 -1
  68. package/dist/providers/data/amazon-bedrock.json +1 -1
  69. package/dist/providers/data/azure-openai-responses.json +1 -1
  70. package/dist/providers/data/baseten.json +1 -1
  71. package/dist/providers/data/cerebras.json +1 -1
  72. package/dist/providers/data/github-copilot.json +1 -1
  73. package/dist/providers/data/openai-codex.json +1 -1
  74. package/dist/providers/data/openai.json +1 -1
  75. package/dist/providers/data/opencode.json +1 -1
  76. package/dist/providers/data/openrouter.json +1 -1
  77. package/dist/providers/data/vercel-ai-gateway.json +1 -1
  78. package/dist/providers/openai-codex.js +1 -1
  79. package/dist/providers/openai-codex.js.map +1 -1
  80. package/dist/providers/openai.d.ts.map +1 -1
  81. package/dist/providers/openai.js +11 -2
  82. package/dist/providers/openai.js.map +1 -1
  83. package/dist/providers/opencode.d.ts +3 -1
  84. package/dist/providers/opencode.d.ts.map +1 -1
  85. package/dist/providers/opencode.js +4 -2
  86. package/dist/providers/opencode.js.map +1 -1
  87. package/dist/providers/vercel-ai-gateway.d.ts.map +1 -1
  88. package/dist/providers/vercel-ai-gateway.js +4 -2
  89. package/dist/providers/vercel-ai-gateway.js.map +1 -1
  90. package/dist/types.d.ts +40 -1
  91. package/dist/types.d.ts.map +1 -1
  92. package/dist/types.js.map +1 -1
  93. package/dist/utils/oauth-page.d.ts +2 -0
  94. package/dist/utils/oauth-page.d.ts.map +1 -0
  95. package/dist/utils/oauth-page.js +2 -0
  96. package/dist/utils/oauth-page.js.map +1 -0
  97. package/dist/utils/retry.d.ts.map +1 -1
  98. package/dist/utils/retry.js +3 -0
  99. package/dist/utils/retry.js.map +1 -1
  100. package/package.json +6 -2
package/CHANGELOG.md CHANGED
@@ -4,6 +4,24 @@ This package is a Bastani fork of `@earendil-works/pi-ai`. Upstream history at t
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.9.25-alpha.1] - 2026-09-29
8
+
9
+ ### Added
10
+
11
+ - Added GPT-6.1 Sol for OpenAI and Codex with supported reasoning efforts, prompt-cache and tool capabilities, and long-context pricing metadata.
12
+ - Added GPT-6.1 Sol to the GitHub Copilot catalog with Copilot's Responses endpoint, supported reasoning efforts, and provider-published context and output limits. Availability remains subject to the account's model policy.
13
+ - Added **Sign in with ChatGPT** for the OpenAI Responses API alongside API-key authentication, separate from Codex subscription login.
14
+ - Added Jev classifiers on Vercel AI Gateway and OpenCode Zen, and provider-reported classifier usage and costs, including billed responses with invalid answers.
15
+ - Added the lightweight `@bastani/pi-ai/models` entry point for model catalog consumers.
16
+ - Added `Model.serviceTiers` and `getServiceTierCost()` for the Fast and Ultrafast tiers a model advertises and their published rates. The OpenAI catalog follows OpenAI's Fast and Ultrafast pricing tables. The Codex catalog follows Codex's per-model tiers: Fast for every model except GPT-5.3 Codex Spark, and Ultrafast for GPT-6 Astra.
17
+ - The OpenAI Responses adapter can send GPT-6 Astra's `ultrafast` tier.
18
+
19
+ ### Changed
20
+
21
+ - The Codex Responses adapter sends `service_tier` only when the model advertises it, following Codex: `flex` always passes through, `default` sends no tier, and an unadvertised tier is left out instead of failing.
22
+ - The OpenAI Responses adapter leaves out a Fast or Ultrafast tier the model doesn't advertise. It sends other tiers as requested.
23
+ - Fast and Ultrafast usage is priced at the served tier's published rates. A model without tier metadata keeps the previous Fast multiplier.
24
+
7
25
  ## [0.9.24] - 2026-09-29
8
26
 
9
27
  ### Added
package/NOTICE.md CHANGED
@@ -6,7 +6,7 @@ monorepo at `packages/ai` and publishes at the same version as `@bastani/atomic`
6
6
 
7
7
  - Upstream package: [`@earendil-works/pi-ai`](https://www.npmjs.com/package/@earendil-works/pi-ai)
8
8
  - Original fork point: `v0.84.2` (`914cf1472e715297caa30db4b9535d534a9eb718`)
9
- - Pi AI fixes and generated image catalog synced through audited upstream `main`: `earendil-works/pi@cb7969d212836b8939001dce159fbd2ed6ad395f`
9
+ - Applicable Pi AI fixes and generated catalogs synced through audited upstream `main`: `earendil-works/pi@1b347794e2a630e4359f2584f4eea388145d0ddf`. Atomic retains its adaptations and does not enable upstream virtual models.
10
10
  - Catalog JSON under `src/providers/data/` is generated at build time from models.dev, matching upstream. It is not committed.
11
11
 
12
12
  Original work is Copyright (c) 2025 Mario Zechner and is licensed under the MIT License.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @bastani/pi-ai
2
2
 
3
- Bastani-branded fork of [`@earendil-works/pi-ai`](https://www.npmjs.com/package/@earendil-works/pi-ai) from [earendil-works/pi](https://github.com/earendil-works/pi). Originally forked at **v0.84.2** (`914cf1472e715297caa30db4b9535d534a9eb718`); upstream Pi AI fixes and the unified model catalog are synced through [`a328aa89ad6e6dc5c5628ff896769532ed3d29df`](https://github.com/earendil-works/pi/commit/a328aa89ad6e6dc5c5628ff896769532ed3d29df). `@bastani/pi-ai` publishes at the same version as Atomic. `npm run build` refreshes the models.dev catalog, same as upstream.
3
+ Bastani-branded fork of [`@earendil-works/pi-ai`](https://www.npmjs.com/package/@earendil-works/pi-ai) from [earendil-works/pi](https://github.com/earendil-works/pi). Originally forked at **v0.84.2** (`914cf1472e715297caa30db4b9535d534a9eb718`); applicable upstream Pi AI fixes and the unified model catalog are synced through [`1b347794e2a630e4359f2584f4eea388145d0ddf`](https://github.com/earendil-works/pi/commit/1b347794e2a630e4359f2584f4eea388145d0ddf). `@bastani/pi-ai` publishes at the same version as Atomic. `npm run build` refreshes the models.dev catalog, same as upstream.
4
4
 
5
5
  The public API is a drop-in replacement: install `@bastani/pi-ai` and import from `@bastani/pi-ai` instead of `@earendil-works/pi-ai`. See [NOTICE.md](NOTICE.md). This package lives in the Atomic monorepo and publishes from `.github/workflows/publish.yml`. The first npm version must be published by hand so trusted publishing can be attached.
6
6
 
@@ -63,10 +63,10 @@ Unified LLM API with provider collections, automatic auth resolution, token and
63
63
 
64
64
  ## Supported Providers
65
65
 
66
- - **OpenAI**
66
+ - **OpenAI** (API key or Sign in with ChatGPT)
67
67
  - **Ant Ling**
68
68
  - **Azure OpenAI (Responses)**
69
- - **OpenAI Codex** (ChatGPT Plus/Pro subscription, requires OAuth, see below)
69
+ - **OpenAI Codex (legacy)** (ChatGPT subscription, requires OAuth, see below)
70
70
  - **Radius** (API key or OAuth, with a dynamically refreshed gateway catalog)
71
71
  - **TypeSafe** (System One classifier API)
72
72
  - **DeepSeek**
@@ -261,6 +261,8 @@ models.setProvider(openrouterProvider());
261
261
 
262
262
  Provider factories import their model catalog and a lazy API wrapper. They do not import other providers. With bundler code splitting, SDK implementations (`@anthropic-ai/sdk`, `openai`, `@google/genai`, etc.) stay in lazy chunks loaded on the first request to a model of that API.
263
263
 
264
+ For a collection without TypeBox, built-in catalogs or provider SDKs, import `createModels` and `createProvider` from `@bastani/pi-ai/models`. Import the provider factories you need separately.
265
+
264
266
  ### All Built-in Providers
265
267
 
266
268
  For apps that want everything (as in Quick Start):
@@ -878,6 +880,8 @@ Classifier models consume structured JSON state and answer one or more typed que
878
880
  | `typesafe` | `jev-latest` | `TYPESAFE_API_KEY` |
879
881
  | `openrouter` | `typesafe/jev-1.13`, `~typesafe/jev-latest` | `OPENROUTER_API_KEY` or OpenRouter OAuth |
880
882
  | `cloudflare-workers-ai` | `typesafe/jev` | `CLOUDFLARE_API_KEY` and `CLOUDFLARE_ACCOUNT_ID` |
883
+ | `vercel-ai-gateway` | `typesafe-ai/jev` | `AI_GATEWAY_API_KEY` |
884
+ | `opencode` | `jev-1.13`, `jev-1.13-free` | `OPENCODE_API_KEY` |
881
885
 
882
886
  ```typescript
883
887
  import { builtinModels } from '@bastani/pi-ai/providers/all';
@@ -913,6 +917,8 @@ console.log(result.answers);
913
917
 
914
918
  The public contract uses `bool` questions and `{ type: "bool", probability }` answers. The TypeSafe adapter translates those to and from its `noul` wire representation. Like image generation, `classify()` resolves to a result with `stopReason: "error"` instead of rejecting for provider, authentication, or response errors.
915
919
 
920
+ System One results include `usage` when the service reports input or output token counts. Costs use the model's catalog pricing. A billed response can retain usage even when its answers are malformed; absent usage means unknown, not zero.
921
+
916
922
  `ClassifierOptions.temperature` divides the answer logits by the given value before they are normalized; values above 1 soften the distribution. APIs that cannot apply it, such as System One, ignore it.
917
923
 
918
924
  ### Chat models on llama.cpp
@@ -993,6 +999,8 @@ for (const block of response.content) {
993
999
 
994
1000
  `xhigh` and `max` are model-specific, opt-in levels. Use `getSupportedThinkingLevels(model)` to determine whether a concrete model exposes either level; models such as GPT-5.6 can expose both.
995
1001
 
1002
+ GPT-6.1 Sol supports `low`, `medium`, `high`, `xhigh` and `max` on OpenAI and Azure Responses. It does not support `off`. The Codex provider also exposes a `minimal` UI alias that sends `low` to the API.
1003
+
996
1004
  ### Provider-Specific Options (stream/complete)
997
1005
 
998
1006
  `models.stream()`/`complete()` accept the owning API's full option set. Use `hasApi()` to narrow a dynamically looked-up model to its API for full option typing:
@@ -1620,7 +1628,7 @@ Browser compatibility notes:
1620
1628
  For small bundles, import only the providers you need:
1621
1629
 
1622
1630
  ```typescript
1623
- import { createModels } from '@bastani/pi-ai';
1631
+ import { createModels } from '@bastani/pi-ai/models';
1624
1632
  import { openaiProvider } from '@bastani/pi-ai/providers/openai';
1625
1633
 
1626
1634
  const models = createModels();
@@ -1693,7 +1701,8 @@ Use this when one process needs different provider settings per request, or when
1693
1701
  Several providers support OAuth authentication instead of static API keys:
1694
1702
 
1695
1703
  - **Anthropic** (Claude Pro/Max subscription)
1696
- - **OpenAI Codex** (ChatGPT Plus/Pro subscription, access to GPT-5.x Codex models)
1704
+ - **OpenAI** (Sign in with ChatGPT, direct Responses API access)
1705
+ - **OpenAI Codex (legacy)** (ChatGPT subscription, Codex Responses access)
1697
1706
  - **GitHub Copilot** (Copilot subscription)
1698
1707
  - **OpenRouter** (OAuth PKCE that mints a user-controlled API key)
1699
1708
 
@@ -1733,6 +1742,8 @@ await models.complete(model, context);
1733
1742
  await models.logout('anthropic');
1734
1743
  ```
1735
1744
 
1745
+ For OpenAI Sign in with ChatGPT, pass a fourth `LoginOptions` argument with `getDeviceId: () => installationUuid`. Persist this UUID and return the same value on later logins. The login registers a user-owned client and stores its issued client ID and granted scopes with the credential. Direct ChatGPT access omits unsupported temperature, output-token limits and cache-retention fields. If its shared subscription limit is exhausted, check [ChatGPT usage](https://chatgpt.com/settings/usage).
1746
+
1736
1747
  ### Vertex AI
1737
1748
 
1738
1749
  Vertex AI models support either a Google Cloud API key or Application Default Credentials (ADC). Its provider-owned API-key login flow can configure either method:
@@ -1773,7 +1784,7 @@ Built-in login and refresh flows are private provider implementations. Use provi
1773
1784
 
1774
1785
  Provider notes:
1775
1786
 
1776
- **OpenAI Codex**: Requires a ChatGPT Plus or Pro subscription. Provides access to GPT-5.x Codex models with extended context windows and reasoning capabilities. The library automatically handles session-based prompt caching when `sessionId` is provided in stream options unless `cacheRetention` is `"none"`. You can set `transport` in stream options to `"sse"`, `"websocket"`, or `"auto"` for Codex Responses transport selection. When using WebSocket with a `sessionId` and cache retention enabled, connections are reused per session and expire after 5 minutes of inactivity.
1787
+ **OpenAI Codex (legacy)**: Requires a ChatGPT subscription with model access. Includes GPT-6.1 Sol and Codex models with extended context windows and reasoning capabilities. The library handles session-based prompt caching when `sessionId` is provided unless `cacheRetention` is `"none"`. Set `transport` to `"sse"`, `"websocket"`, or `"auto"` for Codex Responses transport selection. WebSocket connections with a `sessionId` and caching enabled are reused per session and expire after 5 minutes of inactivity.
1777
1788
 
1778
1789
  Call `cleanupSessionResources(sessionId)` when finished with a Codex session so its pooled WebSocket connection does not keep the process alive. Import it from `@bastani/pi-ai`.
1779
1790
 
@@ -22,7 +22,7 @@ const transport = {
22
22
  label: LABEL,
23
23
  url: (model) => new URL("run", `${model.baseUrl.replace(/\/+$/u, "")}/`),
24
24
  payload: (model, request) => ({ model: model.id, input: request }),
25
- answers: (body) => {
25
+ output: (body) => {
26
26
  if (!isRecord(body))
27
27
  throw new Error(`${LABEL} returned an unexpected response`);
28
28
  if (body.success === false)
@@ -35,7 +35,7 @@ const transport = {
35
35
  }
36
36
  if (!isRecord(run.result))
37
37
  throw new Error(`${LABEL} returned an unexpected response`);
38
- return run.result.answers;
38
+ return run.result;
39
39
  },
40
40
  };
41
41
  /** Cloudflare Workers AI System One classification with public `bool` values mapped to wire-level `noul`. */
@@ -1 +1 @@
1
- {"version":3,"file":"cloudflare-workers-ai-system-one.js","sourceRoot":"","sources":["../../src/api/cloudflare-workers-ai-system-one.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAA2B,MAAM,wBAAwB,CAAC;AAE9F,MAAM,KAAK,GAAG,uBAAuB,CAAC;AAEtC,SAAS,sBAAsB,CAAC,MAAe;IAC9C,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,MAAM;aACrB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;aAClG,MAAM,CAAC,CAAC,OAAO,EAAqB,EAAE,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC;QAChE,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,GAAG,KAAK,WAAW,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IAC1E,CAAC;IACD,OAAO,GAAG,KAAK,iBAAiB,CAAC;AAClC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,SAAS,GAAuB;IACrC,GAAG,EAAE,kCAAkC;IACvC,KAAK,EAAE,KAAK;IACZ,GAAG,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,KAAK,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,CAAC;IACxE,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IAClE,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;QACjB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,kCAAkC,CAAC,CAAC;QACjF,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QACjF,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC;QACxB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,kCAAkC,CAAC,CAAC;QAChF,IAAI,GAAG,CAAC,KAAK,KAAK,WAAW,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,iCAAiC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAChF,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,kCAAkC,CAAC,CAAC;QACvF,OAAO,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC;IAC3B,CAAC;CACD,CAAC;AAEF,6GAA6G;AAC7G,MAAM,CAAC,MAAM,QAAQ,GAA0C,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CAC1F,iBAAiB,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC","sourcesContent":["import type { ClassifierFunction, ClassifierOptions } from \"../types.ts\";\nimport { classifySystemOne, isRecord, type SystemOneTransport } from \"./system-one-shared.ts\";\n\nconst LABEL = \"Cloudflare Workers AI\";\n\nfunction cloudflareErrorMessage(errors: unknown): string {\n\tif (Array.isArray(errors)) {\n\t\tconst messages = errors\n\t\t\t.map((error) => (isRecord(error) && typeof error.message === \"string\" ? error.message : undefined))\n\t\t\t.filter((message): message is string => message !== undefined);\n\t\tif (messages.length > 0) return `${LABEL} error: ${messages.join(\"; \")}`;\n\t}\n\treturn `${LABEL} request failed`;\n}\n\n/**\n * System One models on the Workers AI REST endpoint:\n * `POST /accounts/{account}/ai/run` with `{ model, input }`. The REST API\n * wraps the model output in Cloudflare's API envelope and a run record:\n * `{ success, result: { state: \"Completed\", result: { answers, usage } } }`.\n * https://developers.cloudflare.com/ai/models/typesafe/jev/\n */\nconst transport: SystemOneTransport = {\n\tapi: \"cloudflare-workers-ai-system-one\",\n\tlabel: LABEL,\n\turl: (model) => new URL(\"run\", `${model.baseUrl.replace(/\\/+$/u, \"\")}/`),\n\tpayload: (model, request) => ({ model: model.id, input: request }),\n\tanswers: (body) => {\n\t\tif (!isRecord(body)) throw new Error(`${LABEL} returned an unexpected response`);\n\t\tif (body.success === false) throw new Error(cloudflareErrorMessage(body.errors));\n\t\tconst run = body.result;\n\t\tif (!isRecord(run)) throw new Error(`${LABEL} returned an unexpected response`);\n\t\tif (run.state !== \"Completed\") {\n\t\t\tthrow new Error(`${LABEL} run did not complete (state: ${String(run.state)})`);\n\t\t}\n\t\tif (!isRecord(run.result)) throw new Error(`${LABEL} returned an unexpected response`);\n\t\treturn run.result.answers;\n\t},\n};\n\n/** Cloudflare Workers AI System One classification with public `bool` values mapped to wire-level `noul`. */\nexport const classify: ClassifierFunction<ClassifierOptions> = (model, context, options) =>\n\tclassifySystemOne(transport, model, context, options);\n"]}
1
+ {"version":3,"file":"cloudflare-workers-ai-system-one.js","sourceRoot":"","sources":["../../src/api/cloudflare-workers-ai-system-one.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,QAAQ,EAA2B,MAAM,wBAAwB,CAAC;AAE9F,MAAM,KAAK,GAAG,uBAAuB,CAAC;AAEtC,SAAS,sBAAsB,CAAC,MAAe;IAC9C,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAC3B,MAAM,QAAQ,GAAG,MAAM;aACrB,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,OAAO,KAAK,CAAC,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;aAClG,MAAM,CAAC,CAAC,OAAO,EAAqB,EAAE,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC;QAChE,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;YAAE,OAAO,GAAG,KAAK,WAAW,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;IAC1E,CAAC;IACD,OAAO,GAAG,KAAK,iBAAiB,CAAC;AAClC,CAAC;AAED;;;;;;GAMG;AACH,MAAM,SAAS,GAAuB;IACrC,GAAG,EAAE,kCAAkC;IACvC,KAAK,EAAE,KAAK;IACZ,GAAG,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,GAAG,CAAC,KAAK,EAAE,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,CAAC;IACxE,OAAO,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,KAAK,CAAC,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;IAClE,MAAM,EAAE,CAAC,IAAI,EAAE,EAAE;QAChB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,kCAAkC,CAAC,CAAC;QACjF,IAAI,IAAI,CAAC,OAAO,KAAK,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QACjF,MAAM,GAAG,GAAG,IAAI,CAAC,MAAM,CAAC;QACxB,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,kCAAkC,CAAC,CAAC;QAChF,IAAI,GAAG,CAAC,KAAK,KAAK,WAAW,EAAE,CAAC;YAC/B,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,iCAAiC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAChF,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC;YAAE,MAAM,IAAI,KAAK,CAAC,GAAG,KAAK,kCAAkC,CAAC,CAAC;QACvF,OAAO,GAAG,CAAC,MAAM,CAAC;IACnB,CAAC;CACD,CAAC;AAEF,6GAA6G;AAC7G,MAAM,CAAC,MAAM,QAAQ,GAA0C,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,CAC1F,iBAAiB,CAAC,SAAS,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC","sourcesContent":["import type { ClassifierFunction, ClassifierOptions } from \"../types.ts\";\nimport { classifySystemOne, isRecord, type SystemOneTransport } from \"./system-one-shared.ts\";\n\nconst LABEL = \"Cloudflare Workers AI\";\n\nfunction cloudflareErrorMessage(errors: unknown): string {\n\tif (Array.isArray(errors)) {\n\t\tconst messages = errors\n\t\t\t.map((error) => (isRecord(error) && typeof error.message === \"string\" ? error.message : undefined))\n\t\t\t.filter((message): message is string => message !== undefined);\n\t\tif (messages.length > 0) return `${LABEL} error: ${messages.join(\"; \")}`;\n\t}\n\treturn `${LABEL} request failed`;\n}\n\n/**\n * System One models on the Workers AI REST endpoint:\n * `POST /accounts/{account}/ai/run` with `{ model, input }`. The REST API\n * wraps the model output in Cloudflare's API envelope and a run record:\n * `{ success, result: { state: \"Completed\", result: { answers, usage } } }`.\n * https://developers.cloudflare.com/ai/models/typesafe/jev/\n */\nconst transport: SystemOneTransport = {\n\tapi: \"cloudflare-workers-ai-system-one\",\n\tlabel: LABEL,\n\turl: (model) => new URL(\"run\", `${model.baseUrl.replace(/\\/+$/u, \"\")}/`),\n\tpayload: (model, request) => ({ model: model.id, input: request }),\n\toutput: (body) => {\n\t\tif (!isRecord(body)) throw new Error(`${LABEL} returned an unexpected response`);\n\t\tif (body.success === false) throw new Error(cloudflareErrorMessage(body.errors));\n\t\tconst run = body.result;\n\t\tif (!isRecord(run)) throw new Error(`${LABEL} returned an unexpected response`);\n\t\tif (run.state !== \"Completed\") {\n\t\t\tthrow new Error(`${LABEL} run did not complete (state: ${String(run.state)})`);\n\t\t}\n\t\tif (!isRecord(run.result)) throw new Error(`${LABEL} returned an unexpected response`);\n\t\treturn run.result;\n\t},\n};\n\n/** Cloudflare Workers AI System One classification with public `bool` values mapped to wire-level `noul`. */\nexport const classify: ClassifierFunction<ClassifierOptions> = (model, context, options) =>\n\tclassifySystemOne(transport, model, context, options);\n"]}
@@ -1,9 +1,9 @@
1
- import type { ResponseCreateParamsStreaming } from "openai/resources/responses/responses.js";
2
1
  import type { SimpleStreamOptions, StreamFunction, StreamOptions } from "../types.ts";
2
+ import { type ResponsesServiceTier } from "./openai-responses-shared.ts";
3
3
  export interface OpenAICodexResponsesOptions extends StreamOptions {
4
4
  reasoningEffort?: "none" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
5
5
  reasoningSummary?: "auto" | "concise" | "detailed" | "off" | "on" | null;
6
- serviceTier?: ResponseCreateParamsStreaming["service_tier"];
6
+ serviceTier?: ResponsesServiceTier;
7
7
  textVerbosity?: "low" | "medium" | "high";
8
8
  toolChoice?: "auto" | "none" | "required";
9
9
  }
@@ -1 +1 @@
1
- {"version":3,"file":"openai-codex-responses.d.ts","sourceRoot":"","sources":["../../src/api/openai-codex-responses.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEX,6BAA6B,EAG7B,MAAM,yCAAyC,CAAC;AAIjD,OAAO,KAAK,EAMX,mBAAmB,EACnB,cAAc,EACd,aAAa,EAGb,MAAM,aAAa,CAAC;AAgErB,MAAM,WAAW,2BAA4B,SAAQ,aAAa;IACjE,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;IACnF,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,KAAK,GAAG,IAAI,GAAG,IAAI,CAAC;IACzE,WAAW,CAAC,EAAE,6BAA6B,CAAC,cAAc,CAAC,CAAC;IAC5D,aAAa,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC1C,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC;CAC1C;AAwJD,eAAO,MAAM,MAAM,EAAE,cAAc,CAAC,wBAAwB,EAAE,2BAA2B,CA0QxF,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,cAAc,CAAC,wBAAwB,EAAE,mBAAmB,CAqBtF,CAAC;AAkYF,MAAM,WAAW,8BAA8B;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC5B;AA0BD,wBAAgB,iCAAiC,CAAC,SAAS,EAAE,MAAM,GAAG,8BAA8B,GAAG,SAAS,CAG/G;AAED,wBAAgB,mCAAmC,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAQ5E;AAED,wBAAgB,iCAAiC,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAc1E"}
1
+ {"version":3,"file":"openai-codex-responses.d.ts","sourceRoot":"","sources":["../../src/api/openai-codex-responses.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAMX,mBAAmB,EACnB,cAAc,EACd,aAAa,EAGb,MAAM,aAAa,CAAC;AAwBrB,OAAO,EAMN,KAAK,oBAAoB,EAGzB,MAAM,8BAA8B,CAAC;AAkCtC,MAAM,WAAW,2BAA4B,SAAQ,aAAa;IACjE,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;IACnF,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,UAAU,GAAG,KAAK,GAAG,IAAI,GAAG,IAAI,CAAC;IACzE,WAAW,CAAC,EAAE,oBAAoB,CAAC;IACnC,aAAa,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAC1C,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC;CAC1C;AAwJD,eAAO,MAAM,MAAM,EAAE,cAAc,CAAC,wBAAwB,EAAE,2BAA2B,CA0QxF,CAAC;AAEF,eAAO,MAAM,YAAY,EAAE,cAAc,CAAC,wBAAwB,EAAE,mBAAmB,CAqBtF,CAAC;AA2WF,MAAM,WAAW,8BAA8B;IAC9C,QAAQ,EAAE,MAAM,CAAC;IACjB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,qBAAqB,EAAE,MAAM,CAAC;IAC9B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,YAAY,EAAE,MAAM,CAAC;IACrB,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC5B;AA0BD,wBAAgB,iCAAiC,CAAC,SAAS,EAAE,MAAM,GAAG,8BAA8B,GAAG,SAAS,CAG/G;AAED,wBAAgB,mCAAmC,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAQ5E;AAED,wBAAgB,iCAAiC,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAc1E"}
@@ -13,7 +13,7 @@ import { getDeclaredTools, getInitialSystemMessage, normalizeContext, resolveTra
13
13
  import { uuidv7 } from "../utils/uuid.js";
14
14
  import { createGrammarToolInputProperties } from "./constrained-sampling.js";
15
15
  import { clampOpenAIPromptCacheKey } from "./openai-prompt-cache.js";
16
- import { assertPayloadPreservesFastRoute, convertResponsesMessages, convertResponsesTools, processResponsesStream, resolveRequestedServiceTier, } from "./openai-responses-shared.js";
16
+ import { applyServiceTierPricing, assertPayloadPreservesFastRoute, convertResponsesMessages, convertResponsesTools, processResponsesStream, resolveRequestedServiceTier, codexServiceTierForRequest, } from "./openai-responses-shared.js";
17
17
  import { buildBaseOptions } from "./simple-options.js";
18
18
  // ============================================================================
19
19
  // Configuration
@@ -409,8 +409,7 @@ function buildRequestBody(model, context, options, cacheSessionId, grammarToolIn
409
409
  if (options?.temperature !== undefined) {
410
410
  body.temperature = options.temperature;
411
411
  }
412
- // A fast variant carries its own tier, so a caller that only hands over the model still routes fast.
413
- const requestedServiceTier = resolveRequestedServiceTier(model, options?.serviceTier);
412
+ const requestedServiceTier = resolveCodexRequestServiceTier(model, options?.serviceTier);
414
413
  if (requestedServiceTier !== undefined) {
415
414
  body.service_tier = requestedServiceTier;
416
415
  }
@@ -439,31 +438,12 @@ function buildRequestBody(model, context, options, cacheSessionId, grammarToolIn
439
438
  }
440
439
  return body;
441
440
  }
442
- function getServiceTierCostMultiplier(model, serviceTier) {
443
- // Price against the model that was actually billed upstream, so a `-fast` variant of a
444
- // per-model rate (gpt-5.5) is not silently charged the generic multiplier.
445
- const pricedModelId = model.fastRoute?.baseModelId ?? model.id;
446
- switch (serviceTier) {
447
- case "flex":
448
- return 0.5;
449
- case "priority":
450
- return pricedModelId === "gpt-5.5" ? 2.5 : 2;
451
- default:
452
- return 1;
453
- }
454
- }
455
- function applyServiceTierPricing(usage, serviceTier, model) {
456
- const multiplier = getServiceTierCostMultiplier(model, serviceTier);
457
- if (multiplier === 1)
458
- return;
459
- usage.cost.input *= multiplier;
460
- usage.cost.output *= multiplier;
461
- usage.cost.cacheRead *= multiplier;
462
- usage.cost.cacheWrite *= multiplier;
463
- usage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;
441
+ function resolveCodexRequestServiceTier(model, optionsServiceTier) {
442
+ return codexServiceTierForRequest(model, resolveRequestedServiceTier(model, optionsServiceTier));
464
443
  }
465
444
  function resolveCodexServiceTier(responseServiceTier, requestServiceTier) {
466
- if (responseServiceTier === "default" && (requestServiceTier === "flex" || requestServiceTier === "priority")) {
445
+ if (responseServiceTier === "default" &&
446
+ (requestServiceTier === "flex" || requestServiceTier === "priority" || requestServiceTier === "ultrafast")) {
467
447
  return requestServiceTier;
468
448
  }
469
449
  return responseServiceTier ?? requestServiceTier;
@@ -491,7 +471,7 @@ function resolveCodexWebSocketUrl(baseUrl) {
491
471
  async function processStream(response, output, stream, model, grammarToolInputProperties, options, streamDeadline) {
492
472
  const events = mapCodexEvents(parseSSE(response, streamDeadline.signal), output, model, options?.onProviderStreamEvent);
493
473
  await processResponsesStream(withStreamDeadline(events, streamDeadline.deadlineMs, streamDeadline.abort), output, stream, model, {
494
- serviceTier: resolveRequestedServiceTier(model, options?.serviceTier),
474
+ serviceTier: resolveCodexRequestServiceTier(model, options?.serviceTier),
495
475
  grammarToolInputProperties,
496
476
  resolveServiceTier: resolveCodexServiceTier,
497
477
  applyServiceTierPricing: (usage, serviceTier) => applyServiceTierPricing(usage, serviceTier, model),
@@ -1217,7 +1197,7 @@ async function processWebSocketStream(url, body, headers, output, stream, model,
1217
1197
  try {
1218
1198
  socket.send(JSON.stringify({ type: "response.create", ...requestBody }));
1219
1199
  await processResponsesStream(startWebSocketOutputOnFirstEvent(mapCodexEvents(parseWebSocket(socket, options?.signal, idleTimeoutMs), output, model, options?.onProviderStreamEvent), onStart), output, stream, model, {
1220
- serviceTier: resolveRequestedServiceTier(model, options?.serviceTier),
1200
+ serviceTier: resolveCodexRequestServiceTier(model, options?.serviceTier),
1221
1201
  grammarToolInputProperties,
1222
1202
  resolveServiceTier: resolveCodexServiceTier,
1223
1203
  applyServiceTierPricing: (usage, serviceTier) => applyServiceTierPricing(usage, serviceTier, model),