@mariozechner/pi-ai 0.69.0 → 0.70.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 (38) hide show
  1. package/README.md +4 -1
  2. package/dist/env-api-keys.d.ts +9 -0
  3. package/dist/env-api-keys.d.ts.map +1 -1
  4. package/dist/env-api-keys.js +42 -31
  5. package/dist/env-api-keys.js.map +1 -1
  6. package/dist/models.d.ts +1 -1
  7. package/dist/models.d.ts.map +1 -1
  8. package/dist/models.generated.d.ts +282 -19
  9. package/dist/models.generated.d.ts.map +1 -1
  10. package/dist/models.generated.js +278 -47
  11. package/dist/models.generated.js.map +1 -1
  12. package/dist/models.js +5 -2
  13. package/dist/models.js.map +1 -1
  14. package/dist/providers/anthropic.d.ts.map +1 -1
  15. package/dist/providers/anthropic.js +33 -12
  16. package/dist/providers/anthropic.js.map +1 -1
  17. package/dist/providers/azure-openai-responses.d.ts.map +1 -1
  18. package/dist/providers/azure-openai-responses.js +5 -1
  19. package/dist/providers/azure-openai-responses.js.map +1 -1
  20. package/dist/providers/google-vertex.d.ts.map +1 -1
  21. package/dist/providers/google-vertex.js +34 -13
  22. package/dist/providers/google-vertex.js.map +1 -1
  23. package/dist/providers/openai-codex-responses.d.ts.map +1 -1
  24. package/dist/providers/openai-codex-responses.js +8 -7
  25. package/dist/providers/openai-codex-responses.js.map +1 -1
  26. package/dist/providers/openai-completions.d.ts.map +1 -1
  27. package/dist/providers/openai-completions.js +95 -44
  28. package/dist/providers/openai-completions.js.map +1 -1
  29. package/dist/providers/openai-responses.d.ts.map +1 -1
  30. package/dist/providers/openai-responses.js +24 -20
  31. package/dist/providers/openai-responses.js.map +1 -1
  32. package/dist/providers/simple-options.d.ts.map +1 -1
  33. package/dist/providers/simple-options.js +2 -0
  34. package/dist/providers/simple-options.js.map +1 -1
  35. package/dist/types.d.ts +35 -4
  36. package/dist/types.d.ts.map +1 -1
  37. package/dist/types.js.map +1 -1
  38. package/package.json +1 -1
@@ -1,4 +1,4 @@
1
- import { GoogleGenAI, ThinkingLevel, } from "@google/genai";
1
+ import { GoogleGenAI, ResourceScope, ThinkingLevel, } from "@google/genai";
2
2
  import { calculateCost } from "../models.js";
3
3
  import { AssistantMessageEventStream } from "../utils/event-stream.js";
4
4
  import { sanitizeSurrogates } from "../utils/sanitize-unicode.js";
@@ -251,32 +251,53 @@ export const streamSimpleGoogleVertex = (model, context, options) => {
251
251
  });
252
252
  };
253
253
  function createClient(model, project, location, optionsHeaders) {
254
- const httpOptions = {};
255
- if (model.headers || optionsHeaders) {
256
- httpOptions.headers = { ...model.headers, ...optionsHeaders };
257
- }
258
- const hasHttpOptions = Object.values(httpOptions).some(Boolean);
259
254
  return new GoogleGenAI({
260
255
  vertexai: true,
261
256
  project,
262
257
  location,
263
258
  apiVersion: API_VERSION,
264
- httpOptions: hasHttpOptions ? httpOptions : undefined,
259
+ httpOptions: buildHttpOptions(model, optionsHeaders),
265
260
  });
266
261
  }
267
262
  function createClientWithApiKey(model, apiKey, optionsHeaders) {
268
- const httpOptions = {};
269
- if (model.headers || optionsHeaders) {
270
- httpOptions.headers = { ...model.headers, ...optionsHeaders };
271
- }
272
- const hasHttpOptions = Object.values(httpOptions).some(Boolean);
273
263
  return new GoogleGenAI({
274
264
  vertexai: true,
275
265
  apiKey,
276
266
  apiVersion: API_VERSION,
277
- httpOptions: hasHttpOptions ? httpOptions : undefined,
267
+ httpOptions: buildHttpOptions(model, optionsHeaders),
278
268
  });
279
269
  }
270
+ function buildHttpOptions(model, optionsHeaders) {
271
+ const httpOptions = {};
272
+ const baseUrl = resolveCustomBaseUrl(model.baseUrl);
273
+ if (baseUrl) {
274
+ httpOptions.baseUrl = baseUrl;
275
+ httpOptions.baseUrlResourceScope = ResourceScope.COLLECTION;
276
+ if (baseUrlIncludesApiVersion(baseUrl)) {
277
+ httpOptions.apiVersion = "";
278
+ }
279
+ }
280
+ if (model.headers || optionsHeaders) {
281
+ httpOptions.headers = { ...model.headers, ...optionsHeaders };
282
+ }
283
+ return Object.keys(httpOptions).length > 0 ? httpOptions : undefined;
284
+ }
285
+ function resolveCustomBaseUrl(baseUrl) {
286
+ const trimmed = baseUrl.trim();
287
+ if (!trimmed || trimmed.includes("{location}")) {
288
+ return undefined;
289
+ }
290
+ return trimmed;
291
+ }
292
+ function baseUrlIncludesApiVersion(baseUrl) {
293
+ try {
294
+ const url = new URL(baseUrl);
295
+ return url.pathname.split("/").some((part) => /^v\d+(?:beta\d*)?$/.test(part));
296
+ }
297
+ catch {
298
+ return /(?:^|\/)v\d+(?:beta\d*)?(?:\/|$)/.test(baseUrl);
299
+ }
300
+ }
280
301
  function resolveApiKey(options) {
281
302
  const apiKey = options?.apiKey?.trim() || process.env.GOOGLE_CLOUD_API_KEY?.trim();
282
303
  if (!apiKey || apiKey === GCP_VERTEX_CREDENTIALS_MARKER || isPlaceholderApiKey(apiKey)) {
@@ -1 +1 @@
1
- {"version":3,"file":"google-vertex.js","sourceRoot":"","sources":["../../src/providers/google-vertex.ts"],"names":[],"mappings":"AAAA,OAAO,EAGN,WAAW,EAEX,aAAa,GACb,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAe7C,OAAO,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AACvE,OAAO,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAC;AAElE,OAAO,EACN,eAAe,EACf,YAAY,EACZ,cAAc,EACd,aAAa,EACb,aAAa,EACb,sBAAsB,GACtB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAavE,MAAM,WAAW,GAAG,IAAI,CAAC;AACzB,MAAM,6BAA6B,GAAG,wBAAwB,CAAC;AAE/D,MAAM,kBAAkB,GAA+C;IACtE,0BAA0B,EAAE,aAAa,CAAC,0BAA0B;IACpE,OAAO,EAAE,aAAa,CAAC,OAAO;IAC9B,GAAG,EAAE,aAAa,CAAC,GAAG;IACtB,MAAM,EAAE,aAAa,CAAC,MAAM;IAC5B,IAAI,EAAE,aAAa,CAAC,IAAI;CACxB,CAAC;AAEF,8CAA8C;AAC9C,IAAI,eAAe,GAAG,CAAC,CAAC;AAExB,MAAM,CAAC,MAAM,kBAAkB,GAAyD,CACvF,KAA6B,EAC7B,OAAgB,EAChB,OAA6B,EACC,EAAE,CAAC;IACjC,MAAM,MAAM,GAAG,IAAI,2BAA2B,EAAE,CAAC;IAEjD,CAAC,KAAK,IAAI,EAAE,CAAC;QACZ,MAAM,MAAM,GAAqB;YAChC,IAAI,EAAE,WAAW;YACjB,OAAO,EAAE,EAAE;YACX,GAAG,EAAE,eAAsB;YAC3B,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,KAAK,EAAE,KAAK,CAAC,EAAE;YACf,KAAK,EAAE;gBACN,KAAK,EAAE,CAAC;gBACR,MAAM,EAAE,CAAC;gBACT,SAAS,EAAE,CAAC;gBACZ,UAAU,EAAE,CAAC;gBACb,WAAW,EAAE,CAAC;gBACd,IAAI,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;aACpE;YACD,UAAU,EAAE,MAAM;YAClB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;SACrB,CAAC;QAEF,IAAI,CAAC;YACJ,MAAM,MAAM,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC;YACtC,iGAAiG;YACjG,MAAM,MAAM,GAAG,MAAM;gBACpB,CAAC,CAAC,sBAAsB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC;gBACzD,CAAC,CAAC,YAAY,CAAC,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,EAAE,eAAe,CAAC,OAAO,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;YAC5F,IAAI,MAAM,GAAG,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,CAAC;YAClD,MAAM,UAAU,GAAG,MAAM,OAAO,EAAE,SAAS,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YAC7D,IAAI,UAAU,KAAK,SAAS,EAAE,CAAC;gBAC9B,MAAM,GAAG,UAAuC,CAAC;YAClD,CAAC;YACD,MAAM,YAAY,GAAG,MAAM,MAAM,CAAC,MAAM,CAAC,qBAAqB,CAAC,MAAM,CAAC,CAAC;YAEvE,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;YAChD,IAAI,YAAY,GAAyC,IAAI,CAAC;YAC9D,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC;YAC9B,MAAM,UAAU,GAAG,GAAG,EAAE,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;YAC3C,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,YAAY,EAAE,CAAC;gBACxC,6EAA6E;gBAC7E,iFAAiF;gBACjF,MAAM,CAAC,UAAU,KAAK,KAAK,CAAC,UAAU,CAAC;gBACvC,MAAM,SAAS,GAAG,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,CAAC;gBACxC,IAAI,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;oBAC/B,KAAK,MAAM,IAAI,IAAI,SAAS,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;wBAC5C,IAAI,IAAI,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;4BAC7B,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;4BACxC,IACC,CAAC,YAAY;gCACb,CAAC,UAAU,IAAI,YAAY,CAAC,IAAI,KAAK,UAAU,CAAC;gCAChD,CAAC,CAAC,UAAU,IAAI,YAAY,CAAC,IAAI,KAAK,MAAM,CAAC,EAC5C,CAAC;gCACF,IAAI,YAAY,EAAE,CAAC;oCAClB,IAAI,YAAY,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;wCAClC,MAAM,CAAC,IAAI,CAAC;4CACX,IAAI,EAAE,UAAU;4CAChB,YAAY,EAAE,MAAM,CAAC,MAAM,GAAG,CAAC;4CAC/B,OAAO,EAAE,YAAY,CAAC,IAAI;4CAC1B,OAAO,EAAE,MAAM;yCACf,CAAC,CAAC;oCACJ,CAAC;yCAAM,CAAC;wCACP,MAAM,CAAC,IAAI,CAAC;4CACX,IAAI,EAAE,cAAc;4CACpB,YAAY,EAAE,UAAU,EAAE;4CAC1B,OAAO,EAAE,YAAY,CAAC,QAAQ;4CAC9B,OAAO,EAAE,MAAM;yCACf,CAAC,CAAC;oCACJ,CAAC;gCACF,CAAC;gCACD,IAAI,UAAU,EAAE,CAAC;oCAChB,YAAY,GAAG,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,EAAE,iBAAiB,EAAE,SAAS,EAAE,CAAC;oCAChF,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;oCAClC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,YAAY,EAAE,UAAU,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;gCACtF,CAAC;qCAAM,CAAC;oCACP,YAAY,GAAG,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC;oCAC1C,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;oCAClC,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,YAAY,EAAE,UAAU,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;gCAClF,CAAC;4BACF,CAAC;4BACD,IAAI,YAAY,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;gCACtC,YAAY,CAAC,QAAQ,IAAI,IAAI,CAAC,IAAI,CAAC;gCACnC,YAAY,CAAC,iBAAiB,GAAG,sBAAsB,CACtD,YAAY,CAAC,iBAAiB,EAC9B,IAAI,CAAC,gBAAgB,CACrB,CAAC;gCACF,MAAM,CAAC,IAAI,CAAC;oCACX,IAAI,EAAE,gBAAgB;oCACtB,YAAY,EAAE,UAAU,EAAE;oCAC1B,KAAK,EAAE,IAAI,CAAC,IAAI;oCAChB,OAAO,EAAE,MAAM;iCACf,CAAC,CAAC;4BACJ,CAAC;iCAAM,CAAC;gCACP,YAAY,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,CAAC;gCAC/B,YAAY,CAAC,aAAa,GAAG,sBAAsB,CAClD,YAAY,CAAC,aAAa,EAC1B,IAAI,CAAC,gBAAgB,CACrB,CAAC;gCACF,MAAM,CAAC,IAAI,CAAC;oCACX,IAAI,EAAE,YAAY;oCAClB,YAAY,EAAE,UAAU,EAAE;oCAC1B,KAAK,EAAE,IAAI,CAAC,IAAI;oCAChB,OAAO,EAAE,MAAM;iCACf,CAAC,CAAC;4BACJ,CAAC;wBACF,CAAC;wBAED,IAAI,IAAI,CAAC,YAAY,EAAE,CAAC;4BACvB,IAAI,YAAY,EAAE,CAAC;gCAClB,IAAI,YAAY,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;oCAClC,MAAM,CAAC,IAAI,CAAC;wCACX,IAAI,EAAE,UAAU;wCAChB,YAAY,EAAE,UAAU,EAAE;wCAC1B,OAAO,EAAE,YAAY,CAAC,IAAI;wCAC1B,OAAO,EAAE,MAAM;qCACf,CAAC,CAAC;gCACJ,CAAC;qCAAM,CAAC;oCACP,MAAM,CAAC,IAAI,CAAC;wCACX,IAAI,EAAE,cAAc;wCACpB,YAAY,EAAE,UAAU,EAAE;wCAC1B,OAAO,EAAE,YAAY,CAAC,QAAQ;wCAC9B,OAAO,EAAE,MAAM;qCACf,CAAC,CAAC;gCACJ,CAAC;gCACD,YAAY,GAAG,IAAI,CAAC;4BACrB,CAAC;4BAED,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC;4BACxC,MAAM,UAAU,GACf,CAAC,UAAU,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,IAAI,CAAC,CAAC,EAAE,KAAK,UAAU,CAAC,CAAC;4BACzF,MAAM,UAAU,GAAG,UAAU;gCAC5B,CAAC,CAAC,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,eAAe,EAAE;gCAChE,CAAC,CAAC,UAAU,CAAC;4BAEd,MAAM,QAAQ,GAAa;gCAC1B,IAAI,EAAE,UAAU;gCAChB,EAAE,EAAE,UAAU;gCACd,IAAI,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,IAAI,EAAE;gCAClC,SAAS,EAAG,IAAI,CAAC,YAAY,CAAC,IAA4B,IAAI,EAAE;gCAChE,GAAG,CAAC,IAAI,CAAC,gBAAgB,IAAI,EAAE,gBAAgB,EAAE,IAAI,CAAC,gBAAgB,EAAE,CAAC;6BACzE,CAAC;4BAEF,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;4BAC9B,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,YAAY,EAAE,UAAU,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;4BACrF,MAAM,CAAC,IAAI,CAAC;gCACX,IAAI,EAAE,gBAAgB;gCACtB,YAAY,EAAE,UAAU,EAAE;gCAC1B,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,SAAS,CAAC;gCACzC,OAAO,EAAE,MAAM;6BACf,CAAC,CAAC;4BACH,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,YAAY,EAAE,UAAU,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;wBAC9F,CAAC;oBACF,CAAC;gBACF,CAAC;gBAED,IAAI,SAAS,EAAE,YAAY,EAAE,CAAC;oBAC7B,MAAM,CAAC,UAAU,GAAG,aAAa,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;oBAC1D,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC,EAAE,CAAC;wBACvD,MAAM,CAAC,UAAU,GAAG,SAAS,CAAC;oBAC/B,CAAC;gBACF,CAAC;gBAED,IAAI,KAAK,CAAC,aAAa,EAAE,CAAC;oBACzB,MAAM,CAAC,KAAK,GAAG;wBACd,KAAK,EACJ,CAAC,KAAK,CAAC,aAAa,CAAC,gBAAgB,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,uBAAuB,IAAI,CAAC,CAAC;wBACjG,MAAM,EACL,CAAC,KAAK,CAAC,aAAa,CAAC,oBAAoB,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,aAAa,CAAC,kBAAkB,IAAI,CAAC,CAAC;wBAChG,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC,uBAAuB,IAAI,CAAC;wBAC3D,UAAU,EAAE,CAAC;wBACb,WAAW,EAAE,KAAK,CAAC,aAAa,CAAC,eAAe,IAAI,CAAC;wBACrD,IAAI,EAAE;4BACL,KAAK,EAAE,CAAC;4BACR,MAAM,EAAE,CAAC;4BACT,SAAS,EAAE,CAAC;4BACZ,UAAU,EAAE,CAAC;4BACb,KAAK,EAAE,CAAC;yBACR;qBACD,CAAC;oBACF,aAAa,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;gBACpC,CAAC;YACF,CAAC;YAED,IAAI,YAAY,EAAE,CAAC;gBAClB,IAAI,YAAY,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;oBAClC,MAAM,CAAC,IAAI,CAAC;wBACX,IAAI,EAAE,UAAU;wBAChB,YAAY,EAAE,UAAU,EAAE;wBAC1B,OAAO,EAAE,YAAY,CAAC,IAAI;wBAC1B,OAAO,EAAE,MAAM;qBACf,CAAC,CAAC;gBACJ,CAAC;qBAAM,CAAC;oBACP,MAAM,CAAC,IAAI,CAAC;wBACX,IAAI,EAAE,cAAc;wBACpB,YAAY,EAAE,UAAU,EAAE;wBAC1B,OAAO,EAAE,YAAY,CAAC,QAAQ;wBAC9B,OAAO,EAAE,MAAM;qBACf,CAAC,CAAC;gBACJ,CAAC;YACF,CAAC;YAED,IAAI,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;gBAC9B,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;YACxC,CAAC;YAED,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,IAAI,MAAM,CAAC,UAAU,KAAK,OAAO,EAAE,CAAC;gBACtE,MAAM,IAAI,KAAK,CAAC,2BAA2B,CAAC,CAAC;YAC9C,CAAC;YAED,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,UAAU,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;YAC1E,MAAM,CAAC,GAAG,EAAE,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YAChB,uDAAuD;YACvD,KAAK,MAAM,KAAK,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACpC,IAAI,OAAO,IAAI,KAAK,EAAE,CAAC;oBACtB,OAAQ,KAA4B,CAAC,KAAK,CAAC;gBAC5C,CAAC;YACF,CAAC;YACD,MAAM,CAAC,UAAU,GAAG,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC;YACnE,MAAM,CAAC,YAAY,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YACrF,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;YACzE,MAAM,CAAC,GAAG,EAAE,CAAC;QACd,CAAC;IAAA,CACD,CAAC,EAAE,CAAC;IAEL,OAAO,MAAM,CAAC;AAAA,CACd,CAAC;AAEF,MAAM,CAAC,MAAM,wBAAwB,GAAyD,CAC7F,KAA6B,EAC7B,OAAgB,EAChB,OAA6B,EACC,EAAE,CAAC;IACjC,MAAM,IAAI,GAAG,gBAAgB,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC;IACzD,IAAI,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC;QACzB,OAAO,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE;YACzC,GAAG,IAAI;YACP,QAAQ,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE;SACE,CAAC,CAAC;IAClC,CAAC;IAED,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,SAAS,CAAE,CAAC;IAClD,MAAM,WAAW,GAAG,KAAiD,CAAC;IAEtE,IAAI,iBAAiB,CAAC,WAAW,CAAC,IAAI,mBAAmB,CAAC,WAAW,CAAC,EAAE,CAAC;QACxE,OAAO,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE;YACzC,GAAG,IAAI;YACP,QAAQ,EAAE;gBACT,OAAO,EAAE,IAAI;gBACb,KAAK,EAAE,uBAAuB,CAAC,MAAM,EAAE,WAAW,CAAC;aACnD;SAC6B,CAAC,CAAC;IAClC,CAAC;IAED,OAAO,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE;QACzC,GAAG,IAAI;QACP,QAAQ,EAAE;YACT,OAAO,EAAE,IAAI;YACb,YAAY,EAAE,eAAe,CAAC,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,eAAe,CAAC;SAC3E;KAC6B,CAAC,CAAC;AAAA,CACjC,CAAC;AAEF,SAAS,YAAY,CACpB,KAA6B,EAC7B,OAAe,EACf,QAAgB,EAChB,cAAuC,EACzB;IACd,MAAM,WAAW,GAAyC,EAAE,CAAC;IAE7D,IAAI,KAAK,CAAC,OAAO,IAAI,cAAc,EAAE,CAAC;QACrC,WAAW,CAAC,OAAO,GAAG,EAAE,GAAG,KAAK,CAAC,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAC/D,CAAC;IAED,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAEhE,OAAO,IAAI,WAAW,CAAC;QACtB,QAAQ,EAAE,IAAI;QACd,OAAO;QACP,QAAQ;QACR,UAAU,EAAE,WAAW;QACvB,WAAW,EAAE,cAAc,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS;KACrD,CAAC,CAAC;AAAA,CACH;AAED,SAAS,sBAAsB,CAC9B,KAA6B,EAC7B,MAAc,EACd,cAAuC,EACzB;IACd,MAAM,WAAW,GAAyC,EAAE,CAAC;IAE7D,IAAI,KAAK,CAAC,OAAO,IAAI,cAAc,EAAE,CAAC;QACrC,WAAW,CAAC,OAAO,GAAG,EAAE,GAAG,KAAK,CAAC,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAC/D,CAAC;IAED,MAAM,cAAc,GAAG,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IAEhE,OAAO,IAAI,WAAW,CAAC;QACtB,QAAQ,EAAE,IAAI;QACd,MAAM;QACN,UAAU,EAAE,WAAW;QACvB,WAAW,EAAE,cAAc,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS;KACrD,CAAC,CAAC;AAAA,CACH;AAED,SAAS,aAAa,CAAC,OAA6B,EAAsB;IACzE,MAAM,MAAM,GAAG,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,IAAI,EAAE,CAAC;IACnF,IAAI,CAAC,MAAM,IAAI,MAAM,KAAK,6BAA6B,IAAI,mBAAmB,CAAC,MAAM,CAAC,EAAE,CAAC;QACxF,OAAO,SAAS,CAAC;IAClB,CAAC;IACD,OAAO,MAAM,CAAC;AAAA,CACd;AAED,SAAS,mBAAmB,CAAC,MAAc,EAAW;IACrD,OAAO,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AAAA,CAChC;AAED,SAAS,cAAc,CAAC,OAA6B,EAAU;IAC9D,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;IACnG,IAAI,CAAC,OAAO,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CACd,sGAAsG,CACtG,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AAAA,CACf;AAED,SAAS,eAAe,CAAC,OAA6B,EAAU;IAC/D,MAAM,QAAQ,GAAG,OAAO,EAAE,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC;IACxE,IAAI,CAAC,QAAQ,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,uFAAuF,CAAC,CAAC;IAC1G,CAAC;IACD,OAAO,QAAQ,CAAC;AAAA,CAChB;AAED,SAAS,WAAW,CACnB,KAA6B,EAC7B,OAAgB,EAChB,OAAO,GAAwB,EAAE,EACL;IAC5B,MAAM,QAAQ,GAAG,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IAEjD,MAAM,gBAAgB,GAA0B,EAAE,CAAC;IACnD,IAAI,OAAO,CAAC,WAAW,KAAK,SAAS,EAAE,CAAC;QACvC,gBAAgB,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC;IACpD,CAAC;IACD,IAAI,OAAO,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;QACrC,gBAAgB,CAAC,eAAe,GAAG,OAAO,CAAC,SAAS,CAAC;IACtD,CAAC;IAED,MAAM,MAAM,GAA0B;QACrC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,gBAAgB,CAAC;QACjE,GAAG,CAAC,OAAO,CAAC,YAAY,IAAI,EAAE,iBAAiB,EAAE,kBAAkB,CAAC,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC;QAC5F,GAAG,CAAC,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;KACxF,CAAC;IAEF,IAAI,OAAO,CAAC,KAAK,IAAI,OAAO,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;QACrE,MAAM,CAAC,UAAU,GAAG;YACnB,qBAAqB,EAAE;gBACtB,IAAI,EAAE,aAAa,CAAC,OAAO,CAAC,UAAU,CAAC;aACvC;SACD,CAAC;IACH,CAAC;SAAM,CAAC;QACP,MAAM,CAAC,UAAU,GAAG,SAAS,CAAC;IAC/B,CAAC;IAED,IAAI,OAAO,CAAC,QAAQ,EAAE,OAAO,IAAI,KAAK,CAAC,SAAS,EAAE,CAAC;QAClD,MAAM,cAAc,GAAmB,EAAE,eAAe,EAAE,IAAI,EAAE,CAAC;QACjE,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;YAC1C,cAAc,CAAC,aAAa,GAAG,kBAAkB,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;QAC3E,CAAC;aAAM,IAAI,OAAO,CAAC,QAAQ,CAAC,YAAY,KAAK,SAAS,EAAE,CAAC;YACxD,cAAc,CAAC,cAAc,GAAG,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAC;QAC/D,CAAC;QACD,MAAM,CAAC,cAAc,GAAG,cAAc,CAAC;IACxC,CAAC;SAAM,IAAI,KAAK,CAAC,SAAS,IAAI,OAAO,CAAC,QAAQ,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;QAC7E,MAAM,CAAC,cAAc,GAAG,yBAAyB,CAAC,KAAK,CAAC,CAAC;IAC1D,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACpB,IAAI,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YAC5B,MAAM,IAAI,KAAK,CAAC,iBAAiB,CAAC,CAAC;QACpC,CAAC;QACD,MAAM,CAAC,WAAW,GAAG,OAAO,CAAC,MAAM,CAAC;IACrC,CAAC;IAED,MAAM,MAAM,GAA8B;QACzC,KAAK,EAAE,KAAK,CAAC,EAAE;QACf,QAAQ;QACR,MAAM;KACN,CAAC;IAEF,OAAO,MAAM,CAAC;AAAA,CACd;AAID,SAAS,iBAAiB,CAAC,KAAoC,EAAW;IACzE,OAAO,wBAAwB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;AAAA,CAC7D;AAED,SAAS,mBAAmB,CAAC,KAAoC,EAAW;IAC3E,OAAO,0BAA0B,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,CAAC;AAAA,CAC/D;AAED,SAAS,yBAAyB,CAAC,KAA6B,EAAkB;IACjF,uFAAuF;IACvF,yFAAyF;IACzF,oFAAoF;IACpF,MAAM,WAAW,GAAG,KAAiD,CAAC;IACtE,IAAI,iBAAiB,CAAC,WAAW,CAAC,EAAE,CAAC;QACpC,OAAO,EAAE,aAAa,EAAE,aAAa,CAAC,GAAG,EAAE,CAAC;IAC7C,CAAC;IACD,IAAI,mBAAmB,CAAC,WAAW,CAAC,EAAE,CAAC;QACtC,OAAO,EAAE,aAAa,EAAE,aAAa,CAAC,OAAO,EAAE,CAAC;IACjD,CAAC;IAED,wDAAwD;IACxD,OAAO,EAAE,cAAc,EAAE,CAAC,EAAE,CAAC;AAAA,CAC7B;AAED,SAAS,uBAAuB,CAC/B,MAA4B,EAC5B,KAAoC,EACd;IACtB,IAAI,iBAAiB,CAAC,KAAK,CAAC,EAAE,CAAC;QAC9B,QAAQ,MAAM,EAAE,CAAC;YAChB,KAAK,SAAS,CAAC;YACf,KAAK,KAAK;gBACT,OAAO,KAAK,CAAC;YACd,KAAK,QAAQ,CAAC;YACd,KAAK,MAAM;gBACV,OAAO,MAAM,CAAC;QAChB,CAAC;IACF,CAAC;IACD,QAAQ,MAAM,EAAE,CAAC;QAChB,KAAK,SAAS;YACb,OAAO,SAAS,CAAC;QAClB,KAAK,KAAK;YACT,OAAO,KAAK,CAAC;QACd,KAAK,QAAQ;YACZ,OAAO,QAAQ,CAAC;QACjB,KAAK,MAAM;YACV,OAAO,MAAM,CAAC;IAChB,CAAC;AAAA,CACD;AAED,SAAS,eAAe,CACvB,KAAoC,EACpC,MAA4B,EAC5B,aAA+B,EACtB;IACT,IAAI,aAAa,EAAE,CAAC,MAAM,CAAC,KAAK,SAAS,EAAE,CAAC;QAC3C,OAAO,aAAa,CAAC,MAAM,CAAE,CAAC;IAC/B,CAAC;IAED,IAAI,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;QAClC,MAAM,OAAO,GAAyC;YACrD,OAAO,EAAE,GAAG;YACZ,GAAG,EAAE,IAAI;YACT,MAAM,EAAE,IAAI;YACZ,IAAI,EAAE,KAAK;SACX,CAAC;QACF,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC;IACxB,CAAC;IAED,IAAI,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QACpC,MAAM,OAAO,GAAyC;YACrD,OAAO,EAAE,GAAG;YACZ,GAAG,EAAE,IAAI;YACT,MAAM,EAAE,IAAI;YACZ,IAAI,EAAE,KAAK;SACX,CAAC;QACF,OAAO,OAAO,CAAC,MAAM,CAAC,CAAC;IACxB,CAAC;IAED,OAAO,CAAC,CAAC,CAAC;AAAA,CACV","sourcesContent":["import {\n\ttype GenerateContentConfig,\n\ttype GenerateContentParameters,\n\tGoogleGenAI,\n\ttype ThinkingConfig,\n\tThinkingLevel,\n} from \"@google/genai\";\nimport { calculateCost } from \"../models.js\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tContext,\n\tModel,\n\tThinkingLevel as PiThinkingLevel,\n\tSimpleStreamOptions,\n\tStreamFunction,\n\tStreamOptions,\n\tTextContent,\n\tThinkingBudgets,\n\tThinkingContent,\n\tToolCall,\n} from \"../types.js\";\nimport { AssistantMessageEventStream } from \"../utils/event-stream.js\";\nimport { sanitizeSurrogates } from \"../utils/sanitize-unicode.js\";\nimport type { GoogleThinkingLevel } from \"./google-gemini-cli.js\";\nimport {\n\tconvertMessages,\n\tconvertTools,\n\tisThinkingPart,\n\tmapStopReason,\n\tmapToolChoice,\n\tretainThoughtSignature,\n} from \"./google-shared.js\";\nimport { buildBaseOptions, clampReasoning } from \"./simple-options.js\";\n\nexport interface GoogleVertexOptions extends StreamOptions {\n\ttoolChoice?: \"auto\" | \"none\" | \"any\";\n\tthinking?: {\n\t\tenabled: boolean;\n\t\tbudgetTokens?: number; // -1 for dynamic, 0 to disable\n\t\tlevel?: GoogleThinkingLevel;\n\t};\n\tproject?: string;\n\tlocation?: string;\n}\n\nconst API_VERSION = \"v1\";\nconst GCP_VERTEX_CREDENTIALS_MARKER = \"gcp-vertex-credentials\";\n\nconst THINKING_LEVEL_MAP: Record<GoogleThinkingLevel, ThinkingLevel> = {\n\tTHINKING_LEVEL_UNSPECIFIED: ThinkingLevel.THINKING_LEVEL_UNSPECIFIED,\n\tMINIMAL: ThinkingLevel.MINIMAL,\n\tLOW: ThinkingLevel.LOW,\n\tMEDIUM: ThinkingLevel.MEDIUM,\n\tHIGH: ThinkingLevel.HIGH,\n};\n\n// Counter for generating unique tool call IDs\nlet toolCallCounter = 0;\n\nexport const streamGoogleVertex: StreamFunction<\"google-vertex\", GoogleVertexOptions> = (\n\tmodel: Model<\"google-vertex\">,\n\tcontext: Context,\n\toptions?: GoogleVertexOptions,\n): AssistantMessageEventStream => {\n\tconst stream = new AssistantMessageEventStream();\n\n\t(async () => {\n\t\tconst output: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: [],\n\t\t\tapi: \"google-vertex\" as Api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\tstopReason: \"stop\",\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\ttry {\n\t\t\tconst apiKey = resolveApiKey(options);\n\t\t\t// Create the client using either a Vertex API key, if provided, or ADC with project and location\n\t\t\tconst client = apiKey\n\t\t\t\t? createClientWithApiKey(model, apiKey, options?.headers)\n\t\t\t\t: createClient(model, resolveProject(options), resolveLocation(options), options?.headers);\n\t\t\tlet params = buildParams(model, context, options);\n\t\t\tconst nextParams = await options?.onPayload?.(params, model);\n\t\t\tif (nextParams !== undefined) {\n\t\t\t\tparams = nextParams as GenerateContentParameters;\n\t\t\t}\n\t\t\tconst googleStream = await client.models.generateContentStream(params);\n\n\t\t\tstream.push({ type: \"start\", partial: output });\n\t\t\tlet currentBlock: TextContent | ThinkingContent | null = null;\n\t\t\tconst blocks = output.content;\n\t\t\tconst blockIndex = () => blocks.length - 1;\n\t\t\tfor await (const chunk of googleStream) {\n\t\t\t\t// Vertex uses the same @google/genai GenerateContentResponse type as Gemini.\n\t\t\t\t// responseId is documented there as an output-only identifier for each response.\n\t\t\t\toutput.responseId ||= chunk.responseId;\n\t\t\t\tconst candidate = chunk.candidates?.[0];\n\t\t\t\tif (candidate?.content?.parts) {\n\t\t\t\t\tfor (const part of candidate.content.parts) {\n\t\t\t\t\t\tif (part.text !== undefined) {\n\t\t\t\t\t\t\tconst isThinking = isThinkingPart(part);\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t!currentBlock ||\n\t\t\t\t\t\t\t\t(isThinking && currentBlock.type !== \"thinking\") ||\n\t\t\t\t\t\t\t\t(!isThinking && currentBlock.type !== \"text\")\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tif (currentBlock) {\n\t\t\t\t\t\t\t\t\tif (currentBlock.type === \"text\") {\n\t\t\t\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\t\t\t\t\t\t\tcontentIndex: blocks.length - 1,\n\t\t\t\t\t\t\t\t\t\t\tcontent: currentBlock.text,\n\t\t\t\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\t\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\t\t\t\t\t\tcontent: currentBlock.thinking,\n\t\t\t\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (isThinking) {\n\t\t\t\t\t\t\t\t\tcurrentBlock = { type: \"thinking\", thinking: \"\", thinkingSignature: undefined };\n\t\t\t\t\t\t\t\t\toutput.content.push(currentBlock);\n\t\t\t\t\t\t\t\t\tstream.push({ type: \"thinking_start\", contentIndex: blockIndex(), partial: output });\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tcurrentBlock = { type: \"text\", text: \"\" };\n\t\t\t\t\t\t\t\t\toutput.content.push(currentBlock);\n\t\t\t\t\t\t\t\t\tstream.push({ type: \"text_start\", contentIndex: blockIndex(), partial: output });\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (currentBlock.type === \"thinking\") {\n\t\t\t\t\t\t\t\tcurrentBlock.thinking += part.text;\n\t\t\t\t\t\t\t\tcurrentBlock.thinkingSignature = retainThoughtSignature(\n\t\t\t\t\t\t\t\t\tcurrentBlock.thinkingSignature,\n\t\t\t\t\t\t\t\t\tpart.thoughtSignature,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\t\t\t\tdelta: part.text,\n\t\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tcurrentBlock.text += part.text;\n\t\t\t\t\t\t\t\tcurrentBlock.textSignature = retainThoughtSignature(\n\t\t\t\t\t\t\t\t\tcurrentBlock.textSignature,\n\t\t\t\t\t\t\t\t\tpart.thoughtSignature,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\t\ttype: \"text_delta\",\n\t\t\t\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\t\t\t\tdelta: part.text,\n\t\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (part.functionCall) {\n\t\t\t\t\t\t\tif (currentBlock) {\n\t\t\t\t\t\t\t\tif (currentBlock.type === \"text\") {\n\t\t\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\t\t\t\t\tcontent: currentBlock.text,\n\t\t\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\t\t\t\t\tcontent: currentBlock.thinking,\n\t\t\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tcurrentBlock = null;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst providedId = part.functionCall.id;\n\t\t\t\t\t\t\tconst needsNewId =\n\t\t\t\t\t\t\t\t!providedId || output.content.some((b) => b.type === \"toolCall\" && b.id === providedId);\n\t\t\t\t\t\t\tconst toolCallId = needsNewId\n\t\t\t\t\t\t\t\t? `${part.functionCall.name}_${Date.now()}_${++toolCallCounter}`\n\t\t\t\t\t\t\t\t: providedId;\n\n\t\t\t\t\t\t\tconst toolCall: ToolCall = {\n\t\t\t\t\t\t\t\ttype: \"toolCall\",\n\t\t\t\t\t\t\t\tid: toolCallId,\n\t\t\t\t\t\t\t\tname: part.functionCall.name || \"\",\n\t\t\t\t\t\t\t\targuments: (part.functionCall.args as Record<string, any>) ?? {},\n\t\t\t\t\t\t\t\t...(part.thoughtSignature && { thoughtSignature: part.thoughtSignature }),\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\toutput.content.push(toolCall);\n\t\t\t\t\t\t\tstream.push({ type: \"toolcall_start\", contentIndex: blockIndex(), partial: output });\n\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\t\t\tdelta: JSON.stringify(toolCall.arguments),\n\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tstream.push({ type: \"toolcall_end\", contentIndex: blockIndex(), toolCall, partial: output });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (candidate?.finishReason) {\n\t\t\t\t\toutput.stopReason = mapStopReason(candidate.finishReason);\n\t\t\t\t\tif (output.content.some((b) => b.type === \"toolCall\")) {\n\t\t\t\t\t\toutput.stopReason = \"toolUse\";\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (chunk.usageMetadata) {\n\t\t\t\t\toutput.usage = {\n\t\t\t\t\t\tinput:\n\t\t\t\t\t\t\t(chunk.usageMetadata.promptTokenCount || 0) - (chunk.usageMetadata.cachedContentTokenCount || 0),\n\t\t\t\t\t\toutput:\n\t\t\t\t\t\t\t(chunk.usageMetadata.candidatesTokenCount || 0) + (chunk.usageMetadata.thoughtsTokenCount || 0),\n\t\t\t\t\t\tcacheRead: chunk.usageMetadata.cachedContentTokenCount || 0,\n\t\t\t\t\t\tcacheWrite: 0,\n\t\t\t\t\t\ttotalTokens: chunk.usageMetadata.totalTokenCount || 0,\n\t\t\t\t\t\tcost: {\n\t\t\t\t\t\t\tinput: 0,\n\t\t\t\t\t\t\toutput: 0,\n\t\t\t\t\t\t\tcacheRead: 0,\n\t\t\t\t\t\t\tcacheWrite: 0,\n\t\t\t\t\t\t\ttotal: 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t\tcalculateCost(model, output.usage);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (currentBlock) {\n\t\t\t\tif (currentBlock.type === \"text\") {\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\tcontent: currentBlock.text,\n\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\tcontent: currentBlock.thinking,\n\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (options?.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t}\n\n\t\t\tif (output.stopReason === \"aborted\" || output.stopReason === \"error\") {\n\t\t\t\tthrow new Error(\"An unknown error occurred\");\n\t\t\t}\n\n\t\t\tstream.push({ type: \"done\", reason: output.stopReason, message: output });\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\t// Remove internal index property used during streaming\n\t\t\tfor (const block of output.content) {\n\t\t\t\tif (\"index\" in block) {\n\t\t\t\t\tdelete (block as { index?: number }).index;\n\t\t\t\t}\n\t\t\t}\n\t\t\toutput.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\toutput.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);\n\t\t\tstream.push({ type: \"error\", reason: output.stopReason, error: output });\n\t\t\tstream.end();\n\t\t}\n\t})();\n\n\treturn stream;\n};\n\nexport const streamSimpleGoogleVertex: StreamFunction<\"google-vertex\", SimpleStreamOptions> = (\n\tmodel: Model<\"google-vertex\">,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream => {\n\tconst base = buildBaseOptions(model, options, undefined);\n\tif (!options?.reasoning) {\n\t\treturn streamGoogleVertex(model, context, {\n\t\t\t...base,\n\t\t\tthinking: { enabled: false },\n\t\t} satisfies GoogleVertexOptions);\n\t}\n\n\tconst effort = clampReasoning(options.reasoning)!;\n\tconst geminiModel = model as unknown as Model<\"google-generative-ai\">;\n\n\tif (isGemini3ProModel(geminiModel) || isGemini3FlashModel(geminiModel)) {\n\t\treturn streamGoogleVertex(model, context, {\n\t\t\t...base,\n\t\t\tthinking: {\n\t\t\t\tenabled: true,\n\t\t\t\tlevel: getGemini3ThinkingLevel(effort, geminiModel),\n\t\t\t},\n\t\t} satisfies GoogleVertexOptions);\n\t}\n\n\treturn streamGoogleVertex(model, context, {\n\t\t...base,\n\t\tthinking: {\n\t\t\tenabled: true,\n\t\t\tbudgetTokens: getGoogleBudget(geminiModel, effort, options.thinkingBudgets),\n\t\t},\n\t} satisfies GoogleVertexOptions);\n};\n\nfunction createClient(\n\tmodel: Model<\"google-vertex\">,\n\tproject: string,\n\tlocation: string,\n\toptionsHeaders?: Record<string, string>,\n): GoogleGenAI {\n\tconst httpOptions: { headers?: Record<string, string> } = {};\n\n\tif (model.headers || optionsHeaders) {\n\t\thttpOptions.headers = { ...model.headers, ...optionsHeaders };\n\t}\n\n\tconst hasHttpOptions = Object.values(httpOptions).some(Boolean);\n\n\treturn new GoogleGenAI({\n\t\tvertexai: true,\n\t\tproject,\n\t\tlocation,\n\t\tapiVersion: API_VERSION,\n\t\thttpOptions: hasHttpOptions ? httpOptions : undefined,\n\t});\n}\n\nfunction createClientWithApiKey(\n\tmodel: Model<\"google-vertex\">,\n\tapiKey: string,\n\toptionsHeaders?: Record<string, string>,\n): GoogleGenAI {\n\tconst httpOptions: { headers?: Record<string, string> } = {};\n\n\tif (model.headers || optionsHeaders) {\n\t\thttpOptions.headers = { ...model.headers, ...optionsHeaders };\n\t}\n\n\tconst hasHttpOptions = Object.values(httpOptions).some(Boolean);\n\n\treturn new GoogleGenAI({\n\t\tvertexai: true,\n\t\tapiKey,\n\t\tapiVersion: API_VERSION,\n\t\thttpOptions: hasHttpOptions ? httpOptions : undefined,\n\t});\n}\n\nfunction resolveApiKey(options?: GoogleVertexOptions): string | undefined {\n\tconst apiKey = options?.apiKey?.trim() || process.env.GOOGLE_CLOUD_API_KEY?.trim();\n\tif (!apiKey || apiKey === GCP_VERTEX_CREDENTIALS_MARKER || isPlaceholderApiKey(apiKey)) {\n\t\treturn undefined;\n\t}\n\treturn apiKey;\n}\n\nfunction isPlaceholderApiKey(apiKey: string): boolean {\n\treturn /^<[^>]+>$/.test(apiKey);\n}\n\nfunction resolveProject(options?: GoogleVertexOptions): string {\n\tconst project = options?.project || process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT;\n\tif (!project) {\n\t\tthrow new Error(\n\t\t\t\"Vertex AI requires a project ID. Set GOOGLE_CLOUD_PROJECT/GCLOUD_PROJECT or pass project in options.\",\n\t\t);\n\t}\n\treturn project;\n}\n\nfunction resolveLocation(options?: GoogleVertexOptions): string {\n\tconst location = options?.location || process.env.GOOGLE_CLOUD_LOCATION;\n\tif (!location) {\n\t\tthrow new Error(\"Vertex AI requires a location. Set GOOGLE_CLOUD_LOCATION or pass location in options.\");\n\t}\n\treturn location;\n}\n\nfunction buildParams(\n\tmodel: Model<\"google-vertex\">,\n\tcontext: Context,\n\toptions: GoogleVertexOptions = {},\n): GenerateContentParameters {\n\tconst contents = convertMessages(model, context);\n\n\tconst generationConfig: GenerateContentConfig = {};\n\tif (options.temperature !== undefined) {\n\t\tgenerationConfig.temperature = options.temperature;\n\t}\n\tif (options.maxTokens !== undefined) {\n\t\tgenerationConfig.maxOutputTokens = options.maxTokens;\n\t}\n\n\tconst config: GenerateContentConfig = {\n\t\t...(Object.keys(generationConfig).length > 0 && generationConfig),\n\t\t...(context.systemPrompt && { systemInstruction: sanitizeSurrogates(context.systemPrompt) }),\n\t\t...(context.tools && context.tools.length > 0 && { tools: convertTools(context.tools) }),\n\t};\n\n\tif (context.tools && context.tools.length > 0 && options.toolChoice) {\n\t\tconfig.toolConfig = {\n\t\t\tfunctionCallingConfig: {\n\t\t\t\tmode: mapToolChoice(options.toolChoice),\n\t\t\t},\n\t\t};\n\t} else {\n\t\tconfig.toolConfig = undefined;\n\t}\n\n\tif (options.thinking?.enabled && model.reasoning) {\n\t\tconst thinkingConfig: ThinkingConfig = { includeThoughts: true };\n\t\tif (options.thinking.level !== undefined) {\n\t\t\tthinkingConfig.thinkingLevel = THINKING_LEVEL_MAP[options.thinking.level];\n\t\t} else if (options.thinking.budgetTokens !== undefined) {\n\t\t\tthinkingConfig.thinkingBudget = options.thinking.budgetTokens;\n\t\t}\n\t\tconfig.thinkingConfig = thinkingConfig;\n\t} else if (model.reasoning && options.thinking && !options.thinking.enabled) {\n\t\tconfig.thinkingConfig = getDisabledThinkingConfig(model);\n\t}\n\n\tif (options.signal) {\n\t\tif (options.signal.aborted) {\n\t\t\tthrow new Error(\"Request aborted\");\n\t\t}\n\t\tconfig.abortSignal = options.signal;\n\t}\n\n\tconst params: GenerateContentParameters = {\n\t\tmodel: model.id,\n\t\tcontents,\n\t\tconfig,\n\t};\n\n\treturn params;\n}\n\ntype ClampedThinkingLevel = Exclude<PiThinkingLevel, \"xhigh\">;\n\nfunction isGemini3ProModel(model: Model<\"google-generative-ai\">): boolean {\n\treturn /gemini-3(?:\\.\\d+)?-pro/.test(model.id.toLowerCase());\n}\n\nfunction isGemini3FlashModel(model: Model<\"google-generative-ai\">): boolean {\n\treturn /gemini-3(?:\\.\\d+)?-flash/.test(model.id.toLowerCase());\n}\n\nfunction getDisabledThinkingConfig(model: Model<\"google-vertex\">): ThinkingConfig {\n\t// Google docs: Gemini 3.1 Pro cannot disable thinking, and Gemini 3 Flash / Flash-Lite\n\t// do not support full thinking-off either. For Gemini 3 models, use the lowest supported\n\t// thinkingLevel without includeThoughts so hidden thinking remains invisible to pi.\n\tconst geminiModel = model as unknown as Model<\"google-generative-ai\">;\n\tif (isGemini3ProModel(geminiModel)) {\n\t\treturn { thinkingLevel: ThinkingLevel.LOW };\n\t}\n\tif (isGemini3FlashModel(geminiModel)) {\n\t\treturn { thinkingLevel: ThinkingLevel.MINIMAL };\n\t}\n\n\t// Gemini 2.x supports disabling via thinkingBudget = 0.\n\treturn { thinkingBudget: 0 };\n}\n\nfunction getGemini3ThinkingLevel(\n\teffort: ClampedThinkingLevel,\n\tmodel: Model<\"google-generative-ai\">,\n): GoogleThinkingLevel {\n\tif (isGemini3ProModel(model)) {\n\t\tswitch (effort) {\n\t\t\tcase \"minimal\":\n\t\t\tcase \"low\":\n\t\t\t\treturn \"LOW\";\n\t\t\tcase \"medium\":\n\t\t\tcase \"high\":\n\t\t\t\treturn \"HIGH\";\n\t\t}\n\t}\n\tswitch (effort) {\n\t\tcase \"minimal\":\n\t\t\treturn \"MINIMAL\";\n\t\tcase \"low\":\n\t\t\treturn \"LOW\";\n\t\tcase \"medium\":\n\t\t\treturn \"MEDIUM\";\n\t\tcase \"high\":\n\t\t\treturn \"HIGH\";\n\t}\n}\n\nfunction getGoogleBudget(\n\tmodel: Model<\"google-generative-ai\">,\n\teffort: ClampedThinkingLevel,\n\tcustomBudgets?: ThinkingBudgets,\n): number {\n\tif (customBudgets?.[effort] !== undefined) {\n\t\treturn customBudgets[effort]!;\n\t}\n\n\tif (model.id.includes(\"2.5-pro\")) {\n\t\tconst budgets: Record<ClampedThinkingLevel, number> = {\n\t\t\tminimal: 128,\n\t\t\tlow: 2048,\n\t\t\tmedium: 8192,\n\t\t\thigh: 32768,\n\t\t};\n\t\treturn budgets[effort];\n\t}\n\n\tif (model.id.includes(\"2.5-flash\")) {\n\t\tconst budgets: Record<ClampedThinkingLevel, number> = {\n\t\t\tminimal: 128,\n\t\t\tlow: 2048,\n\t\t\tmedium: 8192,\n\t\t\thigh: 24576,\n\t\t};\n\t\treturn budgets[effort];\n\t}\n\n\treturn -1;\n}\n"]}
1
+ {"version":3,"file":"google-vertex.js","sourceRoot":"","sources":["../../src/providers/google-vertex.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n\ttype GenerateContentConfig,\n\ttype GenerateContentParameters,\n\tGoogleGenAI,\n\ttype HttpOptions,\n\tResourceScope,\n\ttype ThinkingConfig,\n\tThinkingLevel,\n} from \"@google/genai\";\nimport { calculateCost } from \"../models.js\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tContext,\n\tModel,\n\tThinkingLevel as PiThinkingLevel,\n\tSimpleStreamOptions,\n\tStreamFunction,\n\tStreamOptions,\n\tTextContent,\n\tThinkingBudgets,\n\tThinkingContent,\n\tToolCall,\n} from \"../types.js\";\nimport { AssistantMessageEventStream } from \"../utils/event-stream.js\";\nimport { sanitizeSurrogates } from \"../utils/sanitize-unicode.js\";\nimport type { GoogleThinkingLevel } from \"./google-gemini-cli.js\";\nimport {\n\tconvertMessages,\n\tconvertTools,\n\tisThinkingPart,\n\tmapStopReason,\n\tmapToolChoice,\n\tretainThoughtSignature,\n} from \"./google-shared.js\";\nimport { buildBaseOptions, clampReasoning } from \"./simple-options.js\";\n\nexport interface GoogleVertexOptions extends StreamOptions {\n\ttoolChoice?: \"auto\" | \"none\" | \"any\";\n\tthinking?: {\n\t\tenabled: boolean;\n\t\tbudgetTokens?: number; // -1 for dynamic, 0 to disable\n\t\tlevel?: GoogleThinkingLevel;\n\t};\n\tproject?: string;\n\tlocation?: string;\n}\n\nconst API_VERSION = \"v1\";\nconst GCP_VERTEX_CREDENTIALS_MARKER = \"gcp-vertex-credentials\";\n\nconst THINKING_LEVEL_MAP: Record<GoogleThinkingLevel, ThinkingLevel> = {\n\tTHINKING_LEVEL_UNSPECIFIED: ThinkingLevel.THINKING_LEVEL_UNSPECIFIED,\n\tMINIMAL: ThinkingLevel.MINIMAL,\n\tLOW: ThinkingLevel.LOW,\n\tMEDIUM: ThinkingLevel.MEDIUM,\n\tHIGH: ThinkingLevel.HIGH,\n};\n\n// Counter for generating unique tool call IDs\nlet toolCallCounter = 0;\n\nexport const streamGoogleVertex: StreamFunction<\"google-vertex\", GoogleVertexOptions> = (\n\tmodel: Model<\"google-vertex\">,\n\tcontext: Context,\n\toptions?: GoogleVertexOptions,\n): AssistantMessageEventStream => {\n\tconst stream = new AssistantMessageEventStream();\n\n\t(async () => {\n\t\tconst output: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: [],\n\t\t\tapi: \"google-vertex\" as Api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\tstopReason: \"stop\",\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\ttry {\n\t\t\tconst apiKey = resolveApiKey(options);\n\t\t\t// Create the client using either a Vertex API key, if provided, or ADC with project and location\n\t\t\tconst client = apiKey\n\t\t\t\t? createClientWithApiKey(model, apiKey, options?.headers)\n\t\t\t\t: createClient(model, resolveProject(options), resolveLocation(options), options?.headers);\n\t\t\tlet params = buildParams(model, context, options);\n\t\t\tconst nextParams = await options?.onPayload?.(params, model);\n\t\t\tif (nextParams !== undefined) {\n\t\t\t\tparams = nextParams as GenerateContentParameters;\n\t\t\t}\n\t\t\tconst googleStream = await client.models.generateContentStream(params);\n\n\t\t\tstream.push({ type: \"start\", partial: output });\n\t\t\tlet currentBlock: TextContent | ThinkingContent | null = null;\n\t\t\tconst blocks = output.content;\n\t\t\tconst blockIndex = () => blocks.length - 1;\n\t\t\tfor await (const chunk of googleStream) {\n\t\t\t\t// Vertex uses the same @google/genai GenerateContentResponse type as Gemini.\n\t\t\t\t// responseId is documented there as an output-only identifier for each response.\n\t\t\t\toutput.responseId ||= chunk.responseId;\n\t\t\t\tconst candidate = chunk.candidates?.[0];\n\t\t\t\tif (candidate?.content?.parts) {\n\t\t\t\t\tfor (const part of candidate.content.parts) {\n\t\t\t\t\t\tif (part.text !== undefined) {\n\t\t\t\t\t\t\tconst isThinking = isThinkingPart(part);\n\t\t\t\t\t\t\tif (\n\t\t\t\t\t\t\t\t!currentBlock ||\n\t\t\t\t\t\t\t\t(isThinking && currentBlock.type !== \"thinking\") ||\n\t\t\t\t\t\t\t\t(!isThinking && currentBlock.type !== \"text\")\n\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\tif (currentBlock) {\n\t\t\t\t\t\t\t\t\tif (currentBlock.type === \"text\") {\n\t\t\t\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\t\t\t\t\t\t\tcontentIndex: blocks.length - 1,\n\t\t\t\t\t\t\t\t\t\t\tcontent: currentBlock.text,\n\t\t\t\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\t\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\t\t\t\t\t\tcontent: currentBlock.thinking,\n\t\t\t\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (isThinking) {\n\t\t\t\t\t\t\t\t\tcurrentBlock = { type: \"thinking\", thinking: \"\", thinkingSignature: undefined };\n\t\t\t\t\t\t\t\t\toutput.content.push(currentBlock);\n\t\t\t\t\t\t\t\t\tstream.push({ type: \"thinking_start\", contentIndex: blockIndex(), partial: output });\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tcurrentBlock = { type: \"text\", text: \"\" };\n\t\t\t\t\t\t\t\t\toutput.content.push(currentBlock);\n\t\t\t\t\t\t\t\t\tstream.push({ type: \"text_start\", contentIndex: blockIndex(), partial: output });\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif (currentBlock.type === \"thinking\") {\n\t\t\t\t\t\t\t\tcurrentBlock.thinking += part.text;\n\t\t\t\t\t\t\t\tcurrentBlock.thinkingSignature = retainThoughtSignature(\n\t\t\t\t\t\t\t\t\tcurrentBlock.thinkingSignature,\n\t\t\t\t\t\t\t\t\tpart.thoughtSignature,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\t\ttype: \"thinking_delta\",\n\t\t\t\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\t\t\t\tdelta: part.text,\n\t\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tcurrentBlock.text += part.text;\n\t\t\t\t\t\t\t\tcurrentBlock.textSignature = retainThoughtSignature(\n\t\t\t\t\t\t\t\t\tcurrentBlock.textSignature,\n\t\t\t\t\t\t\t\t\tpart.thoughtSignature,\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\t\ttype: \"text_delta\",\n\t\t\t\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\t\t\t\tdelta: part.text,\n\t\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif (part.functionCall) {\n\t\t\t\t\t\t\tif (currentBlock) {\n\t\t\t\t\t\t\t\tif (currentBlock.type === \"text\") {\n\t\t\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\t\t\t\t\tcontent: currentBlock.text,\n\t\t\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\t\t\t\t\tcontent: currentBlock.thinking,\n\t\t\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tcurrentBlock = null;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tconst providedId = part.functionCall.id;\n\t\t\t\t\t\t\tconst needsNewId =\n\t\t\t\t\t\t\t\t!providedId || output.content.some((b) => b.type === \"toolCall\" && b.id === providedId);\n\t\t\t\t\t\t\tconst toolCallId = needsNewId\n\t\t\t\t\t\t\t\t? `${part.functionCall.name}_${Date.now()}_${++toolCallCounter}`\n\t\t\t\t\t\t\t\t: providedId;\n\n\t\t\t\t\t\t\tconst toolCall: ToolCall = {\n\t\t\t\t\t\t\t\ttype: \"toolCall\",\n\t\t\t\t\t\t\t\tid: toolCallId,\n\t\t\t\t\t\t\t\tname: part.functionCall.name || \"\",\n\t\t\t\t\t\t\t\targuments: (part.functionCall.args as Record<string, any>) ?? {},\n\t\t\t\t\t\t\t\t...(part.thoughtSignature && { thoughtSignature: part.thoughtSignature }),\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\toutput.content.push(toolCall);\n\t\t\t\t\t\t\tstream.push({ type: \"toolcall_start\", contentIndex: blockIndex(), partial: output });\n\t\t\t\t\t\t\tstream.push({\n\t\t\t\t\t\t\t\ttype: \"toolcall_delta\",\n\t\t\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\t\t\tdelta: JSON.stringify(toolCall.arguments),\n\t\t\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tstream.push({ type: \"toolcall_end\", contentIndex: blockIndex(), toolCall, partial: output });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (candidate?.finishReason) {\n\t\t\t\t\toutput.stopReason = mapStopReason(candidate.finishReason);\n\t\t\t\t\tif (output.content.some((b) => b.type === \"toolCall\")) {\n\t\t\t\t\t\toutput.stopReason = \"toolUse\";\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tif (chunk.usageMetadata) {\n\t\t\t\t\toutput.usage = {\n\t\t\t\t\t\tinput:\n\t\t\t\t\t\t\t(chunk.usageMetadata.promptTokenCount || 0) - (chunk.usageMetadata.cachedContentTokenCount || 0),\n\t\t\t\t\t\toutput:\n\t\t\t\t\t\t\t(chunk.usageMetadata.candidatesTokenCount || 0) + (chunk.usageMetadata.thoughtsTokenCount || 0),\n\t\t\t\t\t\tcacheRead: chunk.usageMetadata.cachedContentTokenCount || 0,\n\t\t\t\t\t\tcacheWrite: 0,\n\t\t\t\t\t\ttotalTokens: chunk.usageMetadata.totalTokenCount || 0,\n\t\t\t\t\t\tcost: {\n\t\t\t\t\t\t\tinput: 0,\n\t\t\t\t\t\t\toutput: 0,\n\t\t\t\t\t\t\tcacheRead: 0,\n\t\t\t\t\t\t\tcacheWrite: 0,\n\t\t\t\t\t\t\ttotal: 0,\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t\tcalculateCost(model, output.usage);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (currentBlock) {\n\t\t\t\tif (currentBlock.type === \"text\") {\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"text_end\",\n\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\tcontent: currentBlock.text,\n\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t});\n\t\t\t\t} else {\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"thinking_end\",\n\t\t\t\t\t\tcontentIndex: blockIndex(),\n\t\t\t\t\t\tcontent: currentBlock.thinking,\n\t\t\t\t\t\tpartial: output,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (options?.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t}\n\n\t\t\tif (output.stopReason === \"aborted\" || output.stopReason === \"error\") {\n\t\t\t\tthrow new Error(\"An unknown error occurred\");\n\t\t\t}\n\n\t\t\tstream.push({ type: \"done\", reason: output.stopReason, message: output });\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\t// Remove internal index property used during streaming\n\t\t\tfor (const block of output.content) {\n\t\t\t\tif (\"index\" in block) {\n\t\t\t\t\tdelete (block as { index?: number }).index;\n\t\t\t\t}\n\t\t\t}\n\t\t\toutput.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\toutput.errorMessage = error instanceof Error ? error.message : JSON.stringify(error);\n\t\t\tstream.push({ type: \"error\", reason: output.stopReason, error: output });\n\t\t\tstream.end();\n\t\t}\n\t})();\n\n\treturn stream;\n};\n\nexport const streamSimpleGoogleVertex: StreamFunction<\"google-vertex\", SimpleStreamOptions> = (\n\tmodel: Model<\"google-vertex\">,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream => {\n\tconst base = buildBaseOptions(model, options, undefined);\n\tif (!options?.reasoning) {\n\t\treturn streamGoogleVertex(model, context, {\n\t\t\t...base,\n\t\t\tthinking: { enabled: false },\n\t\t} satisfies GoogleVertexOptions);\n\t}\n\n\tconst effort = clampReasoning(options.reasoning)!;\n\tconst geminiModel = model as unknown as Model<\"google-generative-ai\">;\n\n\tif (isGemini3ProModel(geminiModel) || isGemini3FlashModel(geminiModel)) {\n\t\treturn streamGoogleVertex(model, context, {\n\t\t\t...base,\n\t\t\tthinking: {\n\t\t\t\tenabled: true,\n\t\t\t\tlevel: getGemini3ThinkingLevel(effort, geminiModel),\n\t\t\t},\n\t\t} satisfies GoogleVertexOptions);\n\t}\n\n\treturn streamGoogleVertex(model, context, {\n\t\t...base,\n\t\tthinking: {\n\t\t\tenabled: true,\n\t\t\tbudgetTokens: getGoogleBudget(geminiModel, effort, options.thinkingBudgets),\n\t\t},\n\t} satisfies GoogleVertexOptions);\n};\n\nfunction createClient(\n\tmodel: Model<\"google-vertex\">,\n\tproject: string,\n\tlocation: string,\n\toptionsHeaders?: Record<string, string>,\n): GoogleGenAI {\n\treturn new GoogleGenAI({\n\t\tvertexai: true,\n\t\tproject,\n\t\tlocation,\n\t\tapiVersion: API_VERSION,\n\t\thttpOptions: buildHttpOptions(model, optionsHeaders),\n\t});\n}\n\nfunction createClientWithApiKey(\n\tmodel: Model<\"google-vertex\">,\n\tapiKey: string,\n\toptionsHeaders?: Record<string, string>,\n): GoogleGenAI {\n\treturn new GoogleGenAI({\n\t\tvertexai: true,\n\t\tapiKey,\n\t\tapiVersion: API_VERSION,\n\t\thttpOptions: buildHttpOptions(model, optionsHeaders),\n\t});\n}\n\nfunction buildHttpOptions(\n\tmodel: Model<\"google-vertex\">,\n\toptionsHeaders?: Record<string, string>,\n): HttpOptions | undefined {\n\tconst httpOptions: HttpOptions = {};\n\tconst baseUrl = resolveCustomBaseUrl(model.baseUrl);\n\tif (baseUrl) {\n\t\thttpOptions.baseUrl = baseUrl;\n\t\thttpOptions.baseUrlResourceScope = ResourceScope.COLLECTION;\n\t\tif (baseUrlIncludesApiVersion(baseUrl)) {\n\t\t\thttpOptions.apiVersion = \"\";\n\t\t}\n\t}\n\n\tif (model.headers || optionsHeaders) {\n\t\thttpOptions.headers = { ...model.headers, ...optionsHeaders };\n\t}\n\n\treturn Object.keys(httpOptions).length > 0 ? httpOptions : undefined;\n}\n\nfunction resolveCustomBaseUrl(baseUrl: string): string | undefined {\n\tconst trimmed = baseUrl.trim();\n\tif (!trimmed || trimmed.includes(\"{location}\")) {\n\t\treturn undefined;\n\t}\n\treturn trimmed;\n}\n\nfunction baseUrlIncludesApiVersion(baseUrl: string): boolean {\n\ttry {\n\t\tconst url = new URL(baseUrl);\n\t\treturn url.pathname.split(\"/\").some((part) => /^v\\d+(?:beta\\d*)?$/.test(part));\n\t} catch {\n\t\treturn /(?:^|\\/)v\\d+(?:beta\\d*)?(?:\\/|$)/.test(baseUrl);\n\t}\n}\n\nfunction resolveApiKey(options?: GoogleVertexOptions): string | undefined {\n\tconst apiKey = options?.apiKey?.trim() || process.env.GOOGLE_CLOUD_API_KEY?.trim();\n\tif (!apiKey || apiKey === GCP_VERTEX_CREDENTIALS_MARKER || isPlaceholderApiKey(apiKey)) {\n\t\treturn undefined;\n\t}\n\treturn apiKey;\n}\n\nfunction isPlaceholderApiKey(apiKey: string): boolean {\n\treturn /^<[^>]+>$/.test(apiKey);\n}\n\nfunction resolveProject(options?: GoogleVertexOptions): string {\n\tconst project = options?.project || process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT;\n\tif (!project) {\n\t\tthrow new Error(\n\t\t\t\"Vertex AI requires a project ID. Set GOOGLE_CLOUD_PROJECT/GCLOUD_PROJECT or pass project in options.\",\n\t\t);\n\t}\n\treturn project;\n}\n\nfunction resolveLocation(options?: GoogleVertexOptions): string {\n\tconst location = options?.location || process.env.GOOGLE_CLOUD_LOCATION;\n\tif (!location) {\n\t\tthrow new Error(\"Vertex AI requires a location. Set GOOGLE_CLOUD_LOCATION or pass location in options.\");\n\t}\n\treturn location;\n}\n\nfunction buildParams(\n\tmodel: Model<\"google-vertex\">,\n\tcontext: Context,\n\toptions: GoogleVertexOptions = {},\n): GenerateContentParameters {\n\tconst contents = convertMessages(model, context);\n\n\tconst generationConfig: GenerateContentConfig = {};\n\tif (options.temperature !== undefined) {\n\t\tgenerationConfig.temperature = options.temperature;\n\t}\n\tif (options.maxTokens !== undefined) {\n\t\tgenerationConfig.maxOutputTokens = options.maxTokens;\n\t}\n\n\tconst config: GenerateContentConfig = {\n\t\t...(Object.keys(generationConfig).length > 0 && generationConfig),\n\t\t...(context.systemPrompt && { systemInstruction: sanitizeSurrogates(context.systemPrompt) }),\n\t\t...(context.tools && context.tools.length > 0 && { tools: convertTools(context.tools) }),\n\t};\n\n\tif (context.tools && context.tools.length > 0 && options.toolChoice) {\n\t\tconfig.toolConfig = {\n\t\t\tfunctionCallingConfig: {\n\t\t\t\tmode: mapToolChoice(options.toolChoice),\n\t\t\t},\n\t\t};\n\t} else {\n\t\tconfig.toolConfig = undefined;\n\t}\n\n\tif (options.thinking?.enabled && model.reasoning) {\n\t\tconst thinkingConfig: ThinkingConfig = { includeThoughts: true };\n\t\tif (options.thinking.level !== undefined) {\n\t\t\tthinkingConfig.thinkingLevel = THINKING_LEVEL_MAP[options.thinking.level];\n\t\t} else if (options.thinking.budgetTokens !== undefined) {\n\t\t\tthinkingConfig.thinkingBudget = options.thinking.budgetTokens;\n\t\t}\n\t\tconfig.thinkingConfig = thinkingConfig;\n\t} else if (model.reasoning && options.thinking && !options.thinking.enabled) {\n\t\tconfig.thinkingConfig = getDisabledThinkingConfig(model);\n\t}\n\n\tif (options.signal) {\n\t\tif (options.signal.aborted) {\n\t\t\tthrow new Error(\"Request aborted\");\n\t\t}\n\t\tconfig.abortSignal = options.signal;\n\t}\n\n\tconst params: GenerateContentParameters = {\n\t\tmodel: model.id,\n\t\tcontents,\n\t\tconfig,\n\t};\n\n\treturn params;\n}\n\ntype ClampedThinkingLevel = Exclude<PiThinkingLevel, \"xhigh\">;\n\nfunction isGemini3ProModel(model: Model<\"google-generative-ai\">): boolean {\n\treturn /gemini-3(?:\\.\\d+)?-pro/.test(model.id.toLowerCase());\n}\n\nfunction isGemini3FlashModel(model: Model<\"google-generative-ai\">): boolean {\n\treturn /gemini-3(?:\\.\\d+)?-flash/.test(model.id.toLowerCase());\n}\n\nfunction getDisabledThinkingConfig(model: Model<\"google-vertex\">): ThinkingConfig {\n\t// Google docs: Gemini 3.1 Pro cannot disable thinking, and Gemini 3 Flash / Flash-Lite\n\t// do not support full thinking-off either. For Gemini 3 models, use the lowest supported\n\t// thinkingLevel without includeThoughts so hidden thinking remains invisible to pi.\n\tconst geminiModel = model as unknown as Model<\"google-generative-ai\">;\n\tif (isGemini3ProModel(geminiModel)) {\n\t\treturn { thinkingLevel: ThinkingLevel.LOW };\n\t}\n\tif (isGemini3FlashModel(geminiModel)) {\n\t\treturn { thinkingLevel: ThinkingLevel.MINIMAL };\n\t}\n\n\t// Gemini 2.x supports disabling via thinkingBudget = 0.\n\treturn { thinkingBudget: 0 };\n}\n\nfunction getGemini3ThinkingLevel(\n\teffort: ClampedThinkingLevel,\n\tmodel: Model<\"google-generative-ai\">,\n): GoogleThinkingLevel {\n\tif (isGemini3ProModel(model)) {\n\t\tswitch (effort) {\n\t\t\tcase \"minimal\":\n\t\t\tcase \"low\":\n\t\t\t\treturn \"LOW\";\n\t\t\tcase \"medium\":\n\t\t\tcase \"high\":\n\t\t\t\treturn \"HIGH\";\n\t\t}\n\t}\n\tswitch (effort) {\n\t\tcase \"minimal\":\n\t\t\treturn \"MINIMAL\";\n\t\tcase \"low\":\n\t\t\treturn \"LOW\";\n\t\tcase \"medium\":\n\t\t\treturn \"MEDIUM\";\n\t\tcase \"high\":\n\t\t\treturn \"HIGH\";\n\t}\n}\n\nfunction getGoogleBudget(\n\tmodel: Model<\"google-generative-ai\">,\n\teffort: ClampedThinkingLevel,\n\tcustomBudgets?: ThinkingBudgets,\n): number {\n\tif (customBudgets?.[effort] !== undefined) {\n\t\treturn customBudgets[effort]!;\n\t}\n\n\tif (model.id.includes(\"2.5-pro\")) {\n\t\tconst budgets: Record<ClampedThinkingLevel, number> = {\n\t\t\tminimal: 128,\n\t\t\tlow: 2048,\n\t\t\tmedium: 8192,\n\t\t\thigh: 32768,\n\t\t};\n\t\treturn budgets[effort];\n\t}\n\n\tif (model.id.includes(\"2.5-flash\")) {\n\t\tconst budgets: Record<ClampedThinkingLevel, number> = {\n\t\t\tminimal: 128,\n\t\t\tlow: 2048,\n\t\t\tmedium: 8192,\n\t\t\thigh: 24576,\n\t\t};\n\t\treturn budgets[effort];\n\t}\n\n\treturn -1;\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"openai-codex-responses.d.ts","sourceRoot":"","sources":["../../src/providers/openai-codex-responses.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEX,6BAA6B,EAG7B,MAAM,yCAAyC,CAAC;AAkBjD,OAAO,KAAK,EAKX,mBAAmB,EACnB,cAAc,EACd,aAAa,EAEb,MAAM,aAAa,CAAC;AA6BrB,MAAM,WAAW,2BAA4B,SAAQ,aAAa;IACjE,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;IAC3E,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;CAC1C;AAmDD,eAAO,MAAM,0BAA0B,EAAE,cAAc,CAAC,wBAAwB,EAAE,2BAA2B,CAyK5G,CAAC;AAEF,eAAO,MAAM,gCAAgC,EAAE,cAAc,CAAC,wBAAwB,EAAE,mBAAmB,CAiB1G,CAAC","sourcesContent":["import type * as NodeOs from \"node:os\";\nimport type {\n\tTool as OpenAITool,\n\tResponseCreateParamsStreaming,\n\tResponseInput,\n\tResponseStreamEvent,\n} from \"openai/resources/responses/responses.js\";\n\n// NEVER convert to top-level runtime imports - breaks browser/Vite builds (web-ui)\nlet _os: typeof NodeOs | null = null;\n\ntype DynamicImport = (specifier: string) => Promise<unknown>;\n\nconst dynamicImport: DynamicImport = (specifier) => import(specifier);\nconst NODE_OS_SPECIFIER = \"node:\" + \"os\";\n\nif (typeof process !== \"undefined\" && (process.versions?.node || process.versions?.bun)) {\n\tdynamicImport(NODE_OS_SPECIFIER).then((m) => {\n\t\t_os = m as typeof NodeOs;\n\t});\n}\n\nimport { getEnvApiKey } from \"../env-api-keys.js\";\nimport { supportsXhigh } from \"../models.js\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tContext,\n\tModel,\n\tSimpleStreamOptions,\n\tStreamFunction,\n\tStreamOptions,\n\tUsage,\n} from \"../types.js\";\nimport { AssistantMessageEventStream } from \"../utils/event-stream.js\";\nimport { headersToRecord } from \"../utils/headers.js\";\nimport { convertResponsesMessages, convertResponsesTools, processResponsesStream } from \"./openai-responses-shared.js\";\nimport { buildBaseOptions, clampReasoning } from \"./simple-options.js\";\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\nconst DEFAULT_CODEX_BASE_URL = \"https://chatgpt.com/backend-api\";\nconst JWT_CLAIM_PATH = \"https://api.openai.com/auth\" as const;\nconst MAX_RETRIES = 3;\nconst BASE_DELAY_MS = 1000;\nconst CODEX_TOOL_CALL_PROVIDERS = new Set([\"openai\", \"openai-codex\", \"opencode\"]);\n\nconst CODEX_RESPONSE_STATUSES = new Set<CodexResponseStatus>([\n\t\"completed\",\n\t\"incomplete\",\n\t\"failed\",\n\t\"cancelled\",\n\t\"queued\",\n\t\"in_progress\",\n]);\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface OpenAICodexResponsesOptions extends StreamOptions {\n\treasoningEffort?: \"none\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\";\n\treasoningSummary?: \"auto\" | \"concise\" | \"detailed\" | \"off\" | \"on\" | null;\n\tserviceTier?: ResponseCreateParamsStreaming[\"service_tier\"];\n\ttextVerbosity?: \"low\" | \"medium\" | \"high\";\n}\n\ntype CodexResponseStatus = \"completed\" | \"incomplete\" | \"failed\" | \"cancelled\" | \"queued\" | \"in_progress\";\n\ninterface RequestBody {\n\tmodel: string;\n\tstore?: boolean;\n\tstream?: boolean;\n\tinstructions?: string;\n\tinput?: ResponseInput;\n\ttools?: OpenAITool[];\n\ttool_choice?: \"auto\";\n\tparallel_tool_calls?: boolean;\n\ttemperature?: number;\n\treasoning?: { effort?: string; summary?: string };\n\tservice_tier?: ResponseCreateParamsStreaming[\"service_tier\"];\n\ttext?: { verbosity?: string };\n\tinclude?: string[];\n\tprompt_cache_key?: string;\n\t[key: string]: unknown;\n}\n\n// ============================================================================\n// Retry Helpers\n// ============================================================================\n\nfunction isRetryableError(status: number, errorText: string): boolean {\n\tif (status === 429 || status === 500 || status === 502 || status === 503 || status === 504) {\n\t\treturn true;\n\t}\n\treturn /rate.?limit|overloaded|service.?unavailable|upstream.?connect|connection.?refused/i.test(errorText);\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (signal?.aborted) {\n\t\t\treject(new Error(\"Request was aborted\"));\n\t\t\treturn;\n\t\t}\n\t\tconst timeout = setTimeout(resolve, ms);\n\t\tsignal?.addEventListener(\"abort\", () => {\n\t\t\tclearTimeout(timeout);\n\t\t\treject(new Error(\"Request was aborted\"));\n\t\t});\n\t});\n}\n\n// ============================================================================\n// Main Stream Function\n// ============================================================================\n\nexport const streamOpenAICodexResponses: StreamFunction<\"openai-codex-responses\", OpenAICodexResponsesOptions> = (\n\tmodel: Model<\"openai-codex-responses\">,\n\tcontext: Context,\n\toptions?: OpenAICodexResponsesOptions,\n): AssistantMessageEventStream => {\n\tconst stream = new AssistantMessageEventStream();\n\n\t(async () => {\n\t\tconst output: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: [],\n\t\t\tapi: \"openai-codex-responses\" as Api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\tstopReason: \"stop\",\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\ttry {\n\t\t\tconst apiKey = options?.apiKey || getEnvApiKey(model.provider) || \"\";\n\t\t\tif (!apiKey) {\n\t\t\t\tthrow new Error(`No API key for provider: ${model.provider}`);\n\t\t\t}\n\n\t\t\tconst accountId = extractAccountId(apiKey);\n\t\t\tlet body = buildRequestBody(model, context, options);\n\t\t\tconst nextBody = await options?.onPayload?.(body, model);\n\t\t\tif (nextBody !== undefined) {\n\t\t\t\tbody = nextBody as RequestBody;\n\t\t\t}\n\t\t\tconst websocketRequestId = options?.sessionId || createCodexRequestId();\n\t\t\tconst sseHeaders = buildSSEHeaders(model.headers, options?.headers, accountId, apiKey, options?.sessionId);\n\t\t\tconst websocketHeaders = buildWebSocketHeaders(\n\t\t\t\tmodel.headers,\n\t\t\t\toptions?.headers,\n\t\t\t\taccountId,\n\t\t\t\tapiKey,\n\t\t\t\twebsocketRequestId,\n\t\t\t);\n\t\t\tconst bodyJson = JSON.stringify(body);\n\t\t\tconst transport = options?.transport || \"sse\";\n\n\t\t\tif (transport !== \"sse\") {\n\t\t\t\tlet websocketStarted = false;\n\t\t\t\ttry {\n\t\t\t\t\tawait processWebSocketStream(\n\t\t\t\t\t\tresolveCodexWebSocketUrl(model.baseUrl),\n\t\t\t\t\t\tbody,\n\t\t\t\t\t\twebsocketHeaders,\n\t\t\t\t\t\toutput,\n\t\t\t\t\t\tstream,\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\twebsocketStarted = true;\n\t\t\t\t\t\t},\n\t\t\t\t\t\toptions,\n\t\t\t\t\t);\n\n\t\t\t\t\tif (options?.signal?.aborted) {\n\t\t\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t\t\t}\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"done\",\n\t\t\t\t\t\treason: output.stopReason as \"stop\" | \"length\" | \"toolUse\",\n\t\t\t\t\t\tmessage: output,\n\t\t\t\t\t});\n\t\t\t\t\tstream.end();\n\t\t\t\t\treturn;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (transport === \"websocket\" || websocketStarted) {\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Fetch with retry logic for rate limits and transient errors\n\t\t\tlet response: Response | undefined;\n\t\t\tlet lastError: Error | undefined;\n\n\t\t\tfor (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {\n\t\t\t\tif (options?.signal?.aborted) {\n\t\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tresponse = await fetch(resolveCodexUrl(model.baseUrl), {\n\t\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\t\theaders: sseHeaders,\n\t\t\t\t\t\tbody: bodyJson,\n\t\t\t\t\t\tsignal: options?.signal,\n\t\t\t\t\t});\n\t\t\t\t\tawait options?.onResponse?.(\n\t\t\t\t\t\t{ status: response.status, headers: headersToRecord(response.headers) },\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t);\n\n\t\t\t\t\tif (response.ok) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst errorText = await response.text();\n\t\t\t\t\tif (attempt < MAX_RETRIES && isRetryableError(response.status, errorText)) {\n\t\t\t\t\t\tconst delayMs = BASE_DELAY_MS * 2 ** attempt;\n\t\t\t\t\t\tawait sleep(delayMs, options?.signal);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Parse error for friendly message on final attempt or non-retryable error\n\t\t\t\t\tconst fakeResponse = new Response(errorText, {\n\t\t\t\t\t\tstatus: response.status,\n\t\t\t\t\t\tstatusText: response.statusText,\n\t\t\t\t\t});\n\t\t\t\t\tconst info = await parseErrorResponse(fakeResponse);\n\t\t\t\t\tthrow new Error(info.friendlyMessage || info.message);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof Error) {\n\t\t\t\t\t\tif (error.name === \"AbortError\" || error.message === \"Request was aborted\") {\n\t\t\t\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tlastError = error instanceof Error ? error : new Error(String(error));\n\t\t\t\t\t// Network errors are retryable\n\t\t\t\t\tif (attempt < MAX_RETRIES && !lastError.message.includes(\"usage limit\")) {\n\t\t\t\t\t\tconst delayMs = BASE_DELAY_MS * 2 ** attempt;\n\t\t\t\t\t\tawait sleep(delayMs, options?.signal);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tthrow lastError;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!response?.ok) {\n\t\t\t\tthrow lastError ?? new Error(\"Failed after retries\");\n\t\t\t}\n\n\t\t\tif (!response.body) {\n\t\t\t\tthrow new Error(\"No response body\");\n\t\t\t}\n\n\t\t\tstream.push({ type: \"start\", partial: output });\n\t\t\tawait processStream(response, output, stream, model, options);\n\n\t\t\tif (options?.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t}\n\n\t\t\tstream.push({ type: \"done\", reason: output.stopReason as \"stop\" | \"length\" | \"toolUse\", message: output });\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\tfor (const block of output.content) {\n\t\t\t\t// partialJson is only a streaming scratch buffer; never persist it.\n\t\t\t\tdelete (block as { partialJson?: string }).partialJson;\n\t\t\t}\n\t\t\toutput.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\toutput.errorMessage = error instanceof Error ? error.message : String(error);\n\t\t\tstream.push({ type: \"error\", reason: output.stopReason, error: output });\n\t\t\tstream.end();\n\t\t}\n\t})();\n\n\treturn stream;\n};\n\nexport const streamSimpleOpenAICodexResponses: StreamFunction<\"openai-codex-responses\", SimpleStreamOptions> = (\n\tmodel: Model<\"openai-codex-responses\">,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream => {\n\tconst apiKey = options?.apiKey || getEnvApiKey(model.provider);\n\tif (!apiKey) {\n\t\tthrow new Error(`No API key for provider: ${model.provider}`);\n\t}\n\n\tconst base = buildBaseOptions(model, options, apiKey);\n\tconst reasoningEffort = supportsXhigh(model) ? options?.reasoning : clampReasoning(options?.reasoning);\n\n\treturn streamOpenAICodexResponses(model, context, {\n\t\t...base,\n\t\treasoningEffort,\n\t} satisfies OpenAICodexResponsesOptions);\n};\n\n// ============================================================================\n// Request Building\n// ============================================================================\n\nfunction buildRequestBody(\n\tmodel: Model<\"openai-codex-responses\">,\n\tcontext: Context,\n\toptions?: OpenAICodexResponsesOptions,\n): RequestBody {\n\tconst messages = convertResponsesMessages(model, context, CODEX_TOOL_CALL_PROVIDERS, {\n\t\tincludeSystemPrompt: false,\n\t});\n\n\tconst body: RequestBody = {\n\t\tmodel: model.id,\n\t\tstore: false,\n\t\tstream: true,\n\t\tinstructions: context.systemPrompt,\n\t\tinput: messages,\n\t\ttext: { verbosity: options?.textVerbosity || \"medium\" },\n\t\tinclude: [\"reasoning.encrypted_content\"],\n\t\tprompt_cache_key: options?.sessionId,\n\t\ttool_choice: \"auto\",\n\t\tparallel_tool_calls: true,\n\t};\n\n\tif (options?.temperature !== undefined) {\n\t\tbody.temperature = options.temperature;\n\t}\n\n\tif (options?.serviceTier !== undefined) {\n\t\tbody.service_tier = options.serviceTier;\n\t}\n\n\tif (context.tools) {\n\t\tbody.tools = convertResponsesTools(context.tools, { strict: null });\n\t}\n\n\tif (options?.reasoningEffort !== undefined) {\n\t\tbody.reasoning = {\n\t\t\teffort: clampReasoningEffort(model.id, options.reasoningEffort),\n\t\t\tsummary: options.reasoningSummary ?? \"auto\",\n\t\t};\n\t}\n\n\treturn body;\n}\n\nfunction clampReasoningEffort(modelId: string, effort: string): string {\n\tconst id = modelId.includes(\"/\") ? modelId.split(\"/\").pop()! : modelId;\n\tif ((id.startsWith(\"gpt-5.2\") || id.startsWith(\"gpt-5.3\") || id.startsWith(\"gpt-5.4\")) && effort === \"minimal\")\n\t\treturn \"low\";\n\tif (id === \"gpt-5.1\" && effort === \"xhigh\") return \"high\";\n\tif (id === \"gpt-5.1-codex-mini\") return effort === \"high\" || effort === \"xhigh\" ? \"high\" : \"medium\";\n\treturn effort;\n}\n\nfunction getServiceTierCostMultiplier(serviceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined): number {\n\tswitch (serviceTier) {\n\t\tcase \"flex\":\n\t\t\treturn 0.5;\n\t\tcase \"priority\":\n\t\t\treturn 2;\n\t\tdefault:\n\t\t\treturn 1;\n\t}\n}\n\nfunction applyServiceTierPricing(usage: Usage, serviceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined) {\n\tconst multiplier = getServiceTierCostMultiplier(serviceTier);\n\tif (multiplier === 1) return;\n\n\tusage.cost.input *= multiplier;\n\tusage.cost.output *= multiplier;\n\tusage.cost.cacheRead *= multiplier;\n\tusage.cost.cacheWrite *= multiplier;\n\tusage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;\n}\n\nfunction resolveCodexServiceTier(\n\tresponseServiceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n\trequestServiceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n): ResponseCreateParamsStreaming[\"service_tier\"] | undefined {\n\tif (responseServiceTier === \"default\" && (requestServiceTier === \"flex\" || requestServiceTier === \"priority\")) {\n\t\treturn requestServiceTier;\n\t}\n\treturn responseServiceTier ?? requestServiceTier;\n}\n\nfunction resolveCodexUrl(baseUrl?: string): string {\n\tconst raw = baseUrl && baseUrl.trim().length > 0 ? baseUrl : DEFAULT_CODEX_BASE_URL;\n\tconst normalized = raw.replace(/\\/+$/, \"\");\n\tif (normalized.endsWith(\"/codex/responses\")) return normalized;\n\tif (normalized.endsWith(\"/codex\")) return `${normalized}/responses`;\n\treturn `${normalized}/codex/responses`;\n}\n\nfunction resolveCodexWebSocketUrl(baseUrl?: string): string {\n\tconst url = new URL(resolveCodexUrl(baseUrl));\n\tif (url.protocol === \"https:\") url.protocol = \"wss:\";\n\tif (url.protocol === \"http:\") url.protocol = \"ws:\";\n\treturn url.toString();\n}\n\n// ============================================================================\n// Response Processing\n// ============================================================================\n\nasync function processStream(\n\tresponse: Response,\n\toutput: AssistantMessage,\n\tstream: AssistantMessageEventStream,\n\tmodel: Model<\"openai-codex-responses\">,\n\toptions?: OpenAICodexResponsesOptions,\n): Promise<void> {\n\tawait processResponsesStream(mapCodexEvents(parseSSE(response)), output, stream, model, {\n\t\tserviceTier: options?.serviceTier,\n\t\tresolveServiceTier: resolveCodexServiceTier,\n\t\tapplyServiceTierPricing,\n\t});\n}\n\nasync function* mapCodexEvents(events: AsyncIterable<Record<string, unknown>>): AsyncGenerator<ResponseStreamEvent> {\n\tfor await (const event of events) {\n\t\tconst type = typeof event.type === \"string\" ? event.type : undefined;\n\t\tif (!type) continue;\n\n\t\tif (type === \"error\") {\n\t\t\tconst code = (event as { code?: string }).code || \"\";\n\t\t\tconst message = (event as { message?: string }).message || \"\";\n\t\t\tthrow new Error(`Codex error: ${message || code || JSON.stringify(event)}`);\n\t\t}\n\n\t\tif (type === \"response.failed\") {\n\t\t\tconst msg = (event as { response?: { error?: { message?: string } } }).response?.error?.message;\n\t\t\tthrow new Error(msg || \"Codex response failed\");\n\t\t}\n\n\t\tif (type === \"response.done\" || type === \"response.completed\" || type === \"response.incomplete\") {\n\t\t\tconst response = (event as { response?: { status?: unknown } }).response;\n\t\t\tconst normalizedResponse = response\n\t\t\t\t? { ...response, status: normalizeCodexStatus(response.status) }\n\t\t\t\t: response;\n\t\t\tyield { ...event, type: \"response.completed\", response: normalizedResponse } as ResponseStreamEvent;\n\t\t\treturn;\n\t\t}\n\n\t\tyield event as unknown as ResponseStreamEvent;\n\t}\n}\n\nfunction normalizeCodexStatus(status: unknown): CodexResponseStatus | undefined {\n\tif (typeof status !== \"string\") return undefined;\n\treturn CODEX_RESPONSE_STATUSES.has(status as CodexResponseStatus) ? (status as CodexResponseStatus) : undefined;\n}\n\n// ============================================================================\n// SSE Parsing\n// ============================================================================\n\nasync function* parseSSE(response: Response): AsyncGenerator<Record<string, unknown>> {\n\tif (!response.body) return;\n\n\tconst reader = response.body.getReader();\n\tconst decoder = new TextDecoder();\n\tlet buffer = \"\";\n\n\ttry {\n\t\twhile (true) {\n\t\t\tconst { done, value } = await reader.read();\n\t\t\tif (done) break;\n\t\t\tbuffer += decoder.decode(value, { stream: true });\n\n\t\t\tlet idx = buffer.indexOf(\"\\n\\n\");\n\t\t\twhile (idx !== -1) {\n\t\t\t\tconst chunk = buffer.slice(0, idx);\n\t\t\t\tbuffer = buffer.slice(idx + 2);\n\n\t\t\t\tconst dataLines = chunk\n\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t.filter((l) => l.startsWith(\"data:\"))\n\t\t\t\t\t.map((l) => l.slice(5).trim());\n\t\t\t\tif (dataLines.length > 0) {\n\t\t\t\t\tconst data = dataLines.join(\"\\n\").trim();\n\t\t\t\t\tif (data && data !== \"[DONE]\") {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tyield JSON.parse(data);\n\t\t\t\t\t\t} catch {}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tidx = buffer.indexOf(\"\\n\\n\");\n\t\t\t}\n\t\t}\n\t} finally {\n\t\ttry {\n\t\t\tawait reader.cancel();\n\t\t} catch {}\n\t\ttry {\n\t\t\treader.releaseLock();\n\t\t} catch {}\n\t}\n}\n\n// ============================================================================\n// WebSocket Parsing\n// ============================================================================\n\nconst OPENAI_BETA_RESPONSES_WEBSOCKETS = \"responses_websockets=2026-02-06\";\nconst SESSION_WEBSOCKET_CACHE_TTL_MS = 5 * 60 * 1000;\n\ntype WebSocketEventType = \"open\" | \"message\" | \"error\" | \"close\";\ntype WebSocketListener = (event: unknown) => void;\n\ninterface WebSocketLike {\n\tclose(code?: number, reason?: string): void;\n\tsend(data: string): void;\n\taddEventListener(type: WebSocketEventType, listener: WebSocketListener): void;\n\tremoveEventListener(type: WebSocketEventType, listener: WebSocketListener): void;\n}\n\ninterface CachedWebSocketConnection {\n\tsocket: WebSocketLike;\n\tbusy: boolean;\n\tidleTimer?: ReturnType<typeof setTimeout>;\n}\n\nconst websocketSessionCache = new Map<string, CachedWebSocketConnection>();\n\ntype WebSocketConstructor = new (\n\turl: string,\n\tprotocols?: string | string[] | { headers?: Record<string, string> },\n) => WebSocketLike;\n\nfunction getWebSocketConstructor(): WebSocketConstructor | null {\n\tconst ctor = (globalThis as { WebSocket?: unknown }).WebSocket;\n\tif (typeof ctor !== \"function\") return null;\n\treturn ctor as unknown as WebSocketConstructor;\n}\n\nfunction getWebSocketReadyState(socket: WebSocketLike): number | undefined {\n\tconst readyState = (socket as { readyState?: unknown }).readyState;\n\treturn typeof readyState === \"number\" ? readyState : undefined;\n}\n\nfunction isWebSocketReusable(socket: WebSocketLike): boolean {\n\tconst readyState = getWebSocketReadyState(socket);\n\t// If readyState is unavailable, assume the runtime keeps it open/reusable.\n\treturn readyState === undefined || readyState === 1;\n}\n\nfunction closeWebSocketSilently(socket: WebSocketLike, code = 1000, reason = \"done\"): void {\n\ttry {\n\t\tsocket.close(code, reason);\n\t} catch {}\n}\n\nfunction scheduleSessionWebSocketExpiry(sessionId: string, entry: CachedWebSocketConnection): void {\n\tif (entry.idleTimer) {\n\t\tclearTimeout(entry.idleTimer);\n\t}\n\tentry.idleTimer = setTimeout(() => {\n\t\tif (entry.busy) return;\n\t\tcloseWebSocketSilently(entry.socket, 1000, \"idle_timeout\");\n\t\twebsocketSessionCache.delete(sessionId);\n\t}, SESSION_WEBSOCKET_CACHE_TTL_MS);\n}\n\nasync function connectWebSocket(url: string, headers: Headers, signal?: AbortSignal): Promise<WebSocketLike> {\n\tconst WebSocketCtor = getWebSocketConstructor();\n\tif (!WebSocketCtor) {\n\t\tthrow new Error(\"WebSocket transport is not available in this runtime\");\n\t}\n\n\tconst wsHeaders = headersToRecord(headers);\n\tdelete wsHeaders[\"OpenAI-Beta\"];\n\n\treturn new Promise<WebSocketLike>((resolve, reject) => {\n\t\tlet settled = false;\n\t\tlet socket: WebSocketLike;\n\n\t\ttry {\n\t\t\tsocket = new WebSocketCtor(url, { headers: wsHeaders });\n\t\t} catch (error) {\n\t\t\treject(error instanceof Error ? error : new Error(String(error)));\n\t\t\treturn;\n\t\t}\n\n\t\tconst onOpen: WebSocketListener = () => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tcleanup();\n\t\t\tresolve(socket);\n\t\t};\n\t\tconst onError: WebSocketListener = (event) => {\n\t\t\tconst error = extractWebSocketError(event);\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tcleanup();\n\t\t\treject(error);\n\t\t};\n\t\tconst onClose: WebSocketListener = (event) => {\n\t\t\tconst error = extractWebSocketCloseError(event);\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tcleanup();\n\t\t\treject(error);\n\t\t};\n\t\tconst onAbort = () => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tcleanup();\n\t\t\tsocket.close(1000, \"aborted\");\n\t\t\treject(new Error(\"Request was aborted\"));\n\t\t};\n\n\t\tconst cleanup = () => {\n\t\t\tsocket.removeEventListener(\"open\", onOpen);\n\t\t\tsocket.removeEventListener(\"error\", onError);\n\t\t\tsocket.removeEventListener(\"close\", onClose);\n\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t};\n\n\t\tsocket.addEventListener(\"open\", onOpen);\n\t\tsocket.addEventListener(\"error\", onError);\n\t\tsocket.addEventListener(\"close\", onClose);\n\t\tsignal?.addEventListener(\"abort\", onAbort);\n\t});\n}\n\nasync function acquireWebSocket(\n\turl: string,\n\theaders: Headers,\n\tsessionId: string | undefined,\n\tsignal?: AbortSignal,\n): Promise<{ socket: WebSocketLike; release: (options?: { keep?: boolean }) => void }> {\n\tif (!sessionId) {\n\t\tconst socket = await connectWebSocket(url, headers, signal);\n\t\treturn {\n\t\t\tsocket,\n\t\t\trelease: ({ keep } = {}) => {\n\t\t\t\tif (keep === false) {\n\t\t\t\t\tcloseWebSocketSilently(socket);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcloseWebSocketSilently(socket);\n\t\t\t},\n\t\t};\n\t}\n\n\tconst cached = websocketSessionCache.get(sessionId);\n\tif (cached) {\n\t\tif (cached.idleTimer) {\n\t\t\tclearTimeout(cached.idleTimer);\n\t\t\tcached.idleTimer = undefined;\n\t\t}\n\t\tif (!cached.busy && isWebSocketReusable(cached.socket)) {\n\t\t\tcached.busy = true;\n\t\t\treturn {\n\t\t\t\tsocket: cached.socket,\n\t\t\t\trelease: ({ keep } = {}) => {\n\t\t\t\t\tif (!keep || !isWebSocketReusable(cached.socket)) {\n\t\t\t\t\t\tcloseWebSocketSilently(cached.socket);\n\t\t\t\t\t\twebsocketSessionCache.delete(sessionId);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tcached.busy = false;\n\t\t\t\t\tscheduleSessionWebSocketExpiry(sessionId, cached);\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tif (cached.busy) {\n\t\t\tconst socket = await connectWebSocket(url, headers, signal);\n\t\t\treturn {\n\t\t\t\tsocket,\n\t\t\t\trelease: () => {\n\t\t\t\t\tcloseWebSocketSilently(socket);\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tif (!isWebSocketReusable(cached.socket)) {\n\t\t\tcloseWebSocketSilently(cached.socket);\n\t\t\twebsocketSessionCache.delete(sessionId);\n\t\t}\n\t}\n\n\tconst socket = await connectWebSocket(url, headers, signal);\n\tconst entry: CachedWebSocketConnection = { socket, busy: true };\n\twebsocketSessionCache.set(sessionId, entry);\n\treturn {\n\t\tsocket,\n\t\trelease: ({ keep } = {}) => {\n\t\t\tif (!keep || !isWebSocketReusable(entry.socket)) {\n\t\t\t\tcloseWebSocketSilently(entry.socket);\n\t\t\t\tif (entry.idleTimer) clearTimeout(entry.idleTimer);\n\t\t\t\tif (websocketSessionCache.get(sessionId) === entry) {\n\t\t\t\t\twebsocketSessionCache.delete(sessionId);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tentry.busy = false;\n\t\t\tscheduleSessionWebSocketExpiry(sessionId, entry);\n\t\t},\n\t};\n}\n\nfunction extractWebSocketError(event: unknown): Error {\n\tif (event && typeof event === \"object\" && \"message\" in event) {\n\t\tconst message = (event as { message?: unknown }).message;\n\t\tif (typeof message === \"string\" && message.length > 0) {\n\t\t\treturn new Error(message);\n\t\t}\n\t}\n\treturn new Error(\"WebSocket error\");\n}\n\nfunction extractWebSocketCloseError(event: unknown): Error {\n\tif (event && typeof event === \"object\") {\n\t\tconst code = \"code\" in event ? (event as { code?: unknown }).code : undefined;\n\t\tconst reason = \"reason\" in event ? (event as { reason?: unknown }).reason : undefined;\n\t\tconst codeText = typeof code === \"number\" ? ` ${code}` : \"\";\n\t\tconst reasonText = typeof reason === \"string\" && reason.length > 0 ? ` ${reason}` : \"\";\n\t\treturn new Error(`WebSocket closed${codeText}${reasonText}`.trim());\n\t}\n\treturn new Error(\"WebSocket closed\");\n}\n\nasync function decodeWebSocketData(data: unknown): Promise<string | null> {\n\tif (typeof data === \"string\") return data;\n\tif (data instanceof ArrayBuffer) {\n\t\treturn new TextDecoder().decode(new Uint8Array(data));\n\t}\n\tif (ArrayBuffer.isView(data)) {\n\t\tconst view = data as ArrayBufferView;\n\t\treturn new TextDecoder().decode(new Uint8Array(view.buffer, view.byteOffset, view.byteLength));\n\t}\n\tif (data && typeof data === \"object\" && \"arrayBuffer\" in data) {\n\t\tconst blobLike = data as { arrayBuffer: () => Promise<ArrayBuffer> };\n\t\tconst arrayBuffer = await blobLike.arrayBuffer();\n\t\treturn new TextDecoder().decode(new Uint8Array(arrayBuffer));\n\t}\n\treturn null;\n}\n\nasync function* parseWebSocket(socket: WebSocketLike, signal?: AbortSignal): AsyncGenerator<Record<string, unknown>> {\n\tconst queue: Record<string, unknown>[] = [];\n\tlet pending: (() => void) | null = null;\n\tlet done = false;\n\tlet failed: Error | null = null;\n\tlet sawCompletion = false;\n\n\tconst wake = () => {\n\t\tif (!pending) return;\n\t\tconst resolve = pending;\n\t\tpending = null;\n\t\tresolve();\n\t};\n\n\tconst onMessage: WebSocketListener = (event) => {\n\t\tvoid (async () => {\n\t\t\tif (!event || typeof event !== \"object\" || !(\"data\" in event)) return;\n\t\t\tconst text = await decodeWebSocketData((event as { data?: unknown }).data);\n\t\t\tif (!text) return;\n\t\t\ttry {\n\t\t\t\tconst parsed = JSON.parse(text) as Record<string, unknown>;\n\t\t\t\tconst type = typeof parsed.type === \"string\" ? parsed.type : \"\";\n\t\t\t\tif (type === \"response.completed\" || type === \"response.done\" || type === \"response.incomplete\") {\n\t\t\t\t\tsawCompletion = true;\n\t\t\t\t\tdone = true;\n\t\t\t\t}\n\t\t\t\tqueue.push(parsed);\n\t\t\t\twake();\n\t\t\t} catch {}\n\t\t})();\n\t};\n\n\tconst onError: WebSocketListener = (event) => {\n\t\tfailed = extractWebSocketError(event);\n\t\tdone = true;\n\t\twake();\n\t};\n\n\tconst onClose: WebSocketListener = (event) => {\n\t\tif (sawCompletion) {\n\t\t\tdone = true;\n\t\t\twake();\n\t\t\treturn;\n\t\t}\n\t\tif (!failed) {\n\t\t\tfailed = extractWebSocketCloseError(event);\n\t\t}\n\t\tdone = true;\n\t\twake();\n\t};\n\n\tconst onAbort = () => {\n\t\tfailed = new Error(\"Request was aborted\");\n\t\tdone = true;\n\t\twake();\n\t};\n\n\tsocket.addEventListener(\"message\", onMessage);\n\tsocket.addEventListener(\"error\", onError);\n\tsocket.addEventListener(\"close\", onClose);\n\tsignal?.addEventListener(\"abort\", onAbort);\n\n\ttry {\n\t\twhile (true) {\n\t\t\tif (signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t}\n\t\t\tif (queue.length > 0) {\n\t\t\t\tyield queue.shift()!;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (done) break;\n\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\tpending = resolve;\n\t\t\t});\n\t\t}\n\n\t\tif (failed) {\n\t\t\tthrow failed;\n\t\t}\n\t\tif (!sawCompletion) {\n\t\t\tthrow new Error(\"WebSocket stream closed before response.completed\");\n\t\t}\n\t} finally {\n\t\tsocket.removeEventListener(\"message\", onMessage);\n\t\tsocket.removeEventListener(\"error\", onError);\n\t\tsocket.removeEventListener(\"close\", onClose);\n\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t}\n}\n\nasync function processWebSocketStream(\n\turl: string,\n\tbody: RequestBody,\n\theaders: Headers,\n\toutput: AssistantMessage,\n\tstream: AssistantMessageEventStream,\n\tmodel: Model<\"openai-codex-responses\">,\n\tonStart: () => void,\n\toptions?: OpenAICodexResponsesOptions,\n): Promise<void> {\n\tconst { socket, release } = await acquireWebSocket(url, headers, options?.sessionId, options?.signal);\n\tlet keepConnection = true;\n\ttry {\n\t\tsocket.send(JSON.stringify({ type: \"response.create\", ...body }));\n\t\tonStart();\n\t\tstream.push({ type: \"start\", partial: output });\n\t\tawait processResponsesStream(mapCodexEvents(parseWebSocket(socket, options?.signal)), output, stream, model, {\n\t\t\tserviceTier: options?.serviceTier,\n\t\t\tresolveServiceTier: resolveCodexServiceTier,\n\t\t\tapplyServiceTierPricing,\n\t\t});\n\t\tif (options?.signal?.aborted) {\n\t\t\tkeepConnection = false;\n\t\t}\n\t} catch (error) {\n\t\tkeepConnection = false;\n\t\tthrow error;\n\t} finally {\n\t\trelease({ keep: keepConnection });\n\t}\n}\n\n// ============================================================================\n// Error Handling\n// ============================================================================\n\nasync function parseErrorResponse(response: Response): Promise<{ message: string; friendlyMessage?: string }> {\n\tconst raw = await response.text();\n\tlet message = raw || response.statusText || \"Request failed\";\n\tlet friendlyMessage: string | undefined;\n\n\ttry {\n\t\tconst parsed = JSON.parse(raw) as {\n\t\t\terror?: { code?: string; type?: string; message?: string; plan_type?: string; resets_at?: number };\n\t\t};\n\t\tconst err = parsed?.error;\n\t\tif (err) {\n\t\t\tconst code = err.code || err.type || \"\";\n\t\t\tif (/usage_limit_reached|usage_not_included|rate_limit_exceeded/i.test(code) || response.status === 429) {\n\t\t\t\tconst plan = err.plan_type ? ` (${err.plan_type.toLowerCase()} plan)` : \"\";\n\t\t\t\tconst mins = err.resets_at\n\t\t\t\t\t? Math.max(0, Math.round((err.resets_at * 1000 - Date.now()) / 60000))\n\t\t\t\t\t: undefined;\n\t\t\t\tconst when = mins !== undefined ? ` Try again in ~${mins} min.` : \"\";\n\t\t\t\tfriendlyMessage = `You have hit your ChatGPT usage limit${plan}.${when}`.trim();\n\t\t\t}\n\t\t\tmessage = err.message || friendlyMessage || message;\n\t\t}\n\t} catch {}\n\n\treturn { message, friendlyMessage };\n}\n\n// ============================================================================\n// Auth & Headers\n// ============================================================================\n\nfunction extractAccountId(token: string): string {\n\ttry {\n\t\tconst parts = token.split(\".\");\n\t\tif (parts.length !== 3) throw new Error(\"Invalid token\");\n\t\tconst payload = JSON.parse(atob(parts[1]));\n\t\tconst accountId = payload?.[JWT_CLAIM_PATH]?.chatgpt_account_id;\n\t\tif (!accountId) throw new Error(\"No account ID in token\");\n\t\treturn accountId;\n\t} catch {\n\t\tthrow new Error(\"Failed to extract accountId from token\");\n\t}\n}\n\nfunction createCodexRequestId(): string {\n\tif (typeof globalThis.crypto?.randomUUID === \"function\") {\n\t\treturn globalThis.crypto.randomUUID();\n\t}\n\treturn `codex_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction buildBaseCodexHeaders(\n\tinitHeaders: Record<string, string> | undefined,\n\tadditionalHeaders: Record<string, string> | undefined,\n\taccountId: string,\n\ttoken: string,\n): Headers {\n\tconst headers = new Headers(initHeaders);\n\tfor (const [key, value] of Object.entries(additionalHeaders || {})) {\n\t\theaders.set(key, value);\n\t}\n\theaders.set(\"Authorization\", `Bearer ${token}`);\n\theaders.set(\"chatgpt-account-id\", accountId);\n\theaders.set(\"originator\", \"pi\");\n\tconst userAgent = _os ? `pi (${_os.platform()} ${_os.release()}; ${_os.arch()})` : \"pi (browser)\";\n\theaders.set(\"User-Agent\", userAgent);\n\treturn headers;\n}\n\nfunction buildSSEHeaders(\n\tinitHeaders: Record<string, string> | undefined,\n\tadditionalHeaders: Record<string, string> | undefined,\n\taccountId: string,\n\ttoken: string,\n\tsessionId?: string,\n): Headers {\n\tconst headers = buildBaseCodexHeaders(initHeaders, additionalHeaders, accountId, token);\n\theaders.set(\"OpenAI-Beta\", \"responses=experimental\");\n\theaders.set(\"accept\", \"text/event-stream\");\n\theaders.set(\"content-type\", \"application/json\");\n\n\tif (sessionId) {\n\t\theaders.set(\"session_id\", sessionId);\n\t\theaders.set(\"x-client-request-id\", sessionId);\n\t}\n\n\treturn headers;\n}\n\nfunction buildWebSocketHeaders(\n\tinitHeaders: Record<string, string> | undefined,\n\tadditionalHeaders: Record<string, string> | undefined,\n\taccountId: string,\n\ttoken: string,\n\trequestId: string,\n): Headers {\n\tconst headers = buildBaseCodexHeaders(initHeaders, additionalHeaders, accountId, token);\n\theaders.delete(\"accept\");\n\theaders.delete(\"content-type\");\n\theaders.delete(\"OpenAI-Beta\");\n\theaders.delete(\"openai-beta\");\n\theaders.set(\"OpenAI-Beta\", OPENAI_BETA_RESPONSES_WEBSOCKETS);\n\theaders.set(\"x-client-request-id\", requestId);\n\theaders.set(\"session_id\", requestId);\n\treturn headers;\n}\n"]}
1
+ {"version":3,"file":"openai-codex-responses.d.ts","sourceRoot":"","sources":["../../src/providers/openai-codex-responses.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAEX,6BAA6B,EAG7B,MAAM,yCAAyC,CAAC;AAkBjD,OAAO,KAAK,EAKX,mBAAmB,EACnB,cAAc,EACd,aAAa,EAEb,MAAM,aAAa,CAAC;AA6BrB,MAAM,WAAW,2BAA4B,SAAQ,aAAa;IACjE,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;IAC3E,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;CAC1C;AAmDD,eAAO,MAAM,0BAA0B,EAAE,cAAc,CAAC,wBAAwB,EAAE,2BAA2B,CAyK5G,CAAC;AAEF,eAAO,MAAM,gCAAgC,EAAE,cAAc,CAAC,wBAAwB,EAAE,mBAAmB,CAiB1G,CAAC","sourcesContent":["import type * as NodeOs from \"node:os\";\nimport type {\n\tTool as OpenAITool,\n\tResponseCreateParamsStreaming,\n\tResponseInput,\n\tResponseStreamEvent,\n} from \"openai/resources/responses/responses.js\";\n\n// NEVER convert to top-level runtime imports - breaks browser/Vite builds (web-ui)\nlet _os: typeof NodeOs | null = null;\n\ntype DynamicImport = (specifier: string) => Promise<unknown>;\n\nconst dynamicImport: DynamicImport = (specifier) => import(specifier);\nconst NODE_OS_SPECIFIER = \"node:\" + \"os\";\n\nif (typeof process !== \"undefined\" && (process.versions?.node || process.versions?.bun)) {\n\tdynamicImport(NODE_OS_SPECIFIER).then((m) => {\n\t\t_os = m as typeof NodeOs;\n\t});\n}\n\nimport { getEnvApiKey } from \"../env-api-keys.js\";\nimport { supportsXhigh } from \"../models.js\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tContext,\n\tModel,\n\tSimpleStreamOptions,\n\tStreamFunction,\n\tStreamOptions,\n\tUsage,\n} from \"../types.js\";\nimport { AssistantMessageEventStream } from \"../utils/event-stream.js\";\nimport { headersToRecord } from \"../utils/headers.js\";\nimport { convertResponsesMessages, convertResponsesTools, processResponsesStream } from \"./openai-responses-shared.js\";\nimport { buildBaseOptions, clampReasoning } from \"./simple-options.js\";\n\n// ============================================================================\n// Configuration\n// ============================================================================\n\nconst DEFAULT_CODEX_BASE_URL = \"https://chatgpt.com/backend-api\";\nconst JWT_CLAIM_PATH = \"https://api.openai.com/auth\" as const;\nconst MAX_RETRIES = 3;\nconst BASE_DELAY_MS = 1000;\nconst CODEX_TOOL_CALL_PROVIDERS = new Set([\"openai\", \"openai-codex\", \"opencode\"]);\n\nconst CODEX_RESPONSE_STATUSES = new Set<CodexResponseStatus>([\n\t\"completed\",\n\t\"incomplete\",\n\t\"failed\",\n\t\"cancelled\",\n\t\"queued\",\n\t\"in_progress\",\n]);\n\n// ============================================================================\n// Types\n// ============================================================================\n\nexport interface OpenAICodexResponsesOptions extends StreamOptions {\n\treasoningEffort?: \"none\" | \"minimal\" | \"low\" | \"medium\" | \"high\" | \"xhigh\";\n\treasoningSummary?: \"auto\" | \"concise\" | \"detailed\" | \"off\" | \"on\" | null;\n\tserviceTier?: ResponseCreateParamsStreaming[\"service_tier\"];\n\ttextVerbosity?: \"low\" | \"medium\" | \"high\";\n}\n\ntype CodexResponseStatus = \"completed\" | \"incomplete\" | \"failed\" | \"cancelled\" | \"queued\" | \"in_progress\";\n\ninterface RequestBody {\n\tmodel: string;\n\tstore?: boolean;\n\tstream?: boolean;\n\tinstructions?: string;\n\tinput?: ResponseInput;\n\ttools?: OpenAITool[];\n\ttool_choice?: \"auto\";\n\tparallel_tool_calls?: boolean;\n\ttemperature?: number;\n\treasoning?: { effort?: string; summary?: string };\n\tservice_tier?: ResponseCreateParamsStreaming[\"service_tier\"];\n\ttext?: { verbosity?: string };\n\tinclude?: string[];\n\tprompt_cache_key?: string;\n\t[key: string]: unknown;\n}\n\n// ============================================================================\n// Retry Helpers\n// ============================================================================\n\nfunction isRetryableError(status: number, errorText: string): boolean {\n\tif (status === 429 || status === 500 || status === 502 || status === 503 || status === 504) {\n\t\treturn true;\n\t}\n\treturn /rate.?limit|overloaded|service.?unavailable|upstream.?connect|connection.?refused/i.test(errorText);\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n\treturn new Promise((resolve, reject) => {\n\t\tif (signal?.aborted) {\n\t\t\treject(new Error(\"Request was aborted\"));\n\t\t\treturn;\n\t\t}\n\t\tconst timeout = setTimeout(resolve, ms);\n\t\tsignal?.addEventListener(\"abort\", () => {\n\t\t\tclearTimeout(timeout);\n\t\t\treject(new Error(\"Request was aborted\"));\n\t\t});\n\t});\n}\n\n// ============================================================================\n// Main Stream Function\n// ============================================================================\n\nexport const streamOpenAICodexResponses: StreamFunction<\"openai-codex-responses\", OpenAICodexResponsesOptions> = (\n\tmodel: Model<\"openai-codex-responses\">,\n\tcontext: Context,\n\toptions?: OpenAICodexResponsesOptions,\n): AssistantMessageEventStream => {\n\tconst stream = new AssistantMessageEventStream();\n\n\t(async () => {\n\t\tconst output: AssistantMessage = {\n\t\t\trole: \"assistant\",\n\t\t\tcontent: [],\n\t\t\tapi: \"openai-codex-responses\" as Api,\n\t\t\tprovider: model.provider,\n\t\t\tmodel: model.id,\n\t\t\tusage: {\n\t\t\t\tinput: 0,\n\t\t\t\toutput: 0,\n\t\t\t\tcacheRead: 0,\n\t\t\t\tcacheWrite: 0,\n\t\t\t\ttotalTokens: 0,\n\t\t\t\tcost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0, total: 0 },\n\t\t\t},\n\t\t\tstopReason: \"stop\",\n\t\t\ttimestamp: Date.now(),\n\t\t};\n\n\t\ttry {\n\t\t\tconst apiKey = options?.apiKey || getEnvApiKey(model.provider) || \"\";\n\t\t\tif (!apiKey) {\n\t\t\t\tthrow new Error(`No API key for provider: ${model.provider}`);\n\t\t\t}\n\n\t\t\tconst accountId = extractAccountId(apiKey);\n\t\t\tlet body = buildRequestBody(model, context, options);\n\t\t\tconst nextBody = await options?.onPayload?.(body, model);\n\t\t\tif (nextBody !== undefined) {\n\t\t\t\tbody = nextBody as RequestBody;\n\t\t\t}\n\t\t\tconst websocketRequestId = options?.sessionId || createCodexRequestId();\n\t\t\tconst sseHeaders = buildSSEHeaders(model.headers, options?.headers, accountId, apiKey, options?.sessionId);\n\t\t\tconst websocketHeaders = buildWebSocketHeaders(\n\t\t\t\tmodel.headers,\n\t\t\t\toptions?.headers,\n\t\t\t\taccountId,\n\t\t\t\tapiKey,\n\t\t\t\twebsocketRequestId,\n\t\t\t);\n\t\t\tconst bodyJson = JSON.stringify(body);\n\t\t\tconst transport = options?.transport || \"sse\";\n\n\t\t\tif (transport !== \"sse\") {\n\t\t\t\tlet websocketStarted = false;\n\t\t\t\ttry {\n\t\t\t\t\tawait processWebSocketStream(\n\t\t\t\t\t\tresolveCodexWebSocketUrl(model.baseUrl),\n\t\t\t\t\t\tbody,\n\t\t\t\t\t\twebsocketHeaders,\n\t\t\t\t\t\toutput,\n\t\t\t\t\t\tstream,\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\twebsocketStarted = true;\n\t\t\t\t\t\t},\n\t\t\t\t\t\toptions,\n\t\t\t\t\t);\n\n\t\t\t\t\tif (options?.signal?.aborted) {\n\t\t\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t\t\t}\n\t\t\t\t\tstream.push({\n\t\t\t\t\t\ttype: \"done\",\n\t\t\t\t\t\treason: output.stopReason as \"stop\" | \"length\" | \"toolUse\",\n\t\t\t\t\t\tmessage: output,\n\t\t\t\t\t});\n\t\t\t\t\tstream.end();\n\t\t\t\t\treturn;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (transport === \"websocket\" || websocketStarted) {\n\t\t\t\t\t\tthrow error;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Fetch with retry logic for rate limits and transient errors\n\t\t\tlet response: Response | undefined;\n\t\t\tlet lastError: Error | undefined;\n\n\t\t\tfor (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {\n\t\t\t\tif (options?.signal?.aborted) {\n\t\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t\t}\n\n\t\t\t\ttry {\n\t\t\t\t\tresponse = await fetch(resolveCodexUrl(model.baseUrl), {\n\t\t\t\t\t\tmethod: \"POST\",\n\t\t\t\t\t\theaders: sseHeaders,\n\t\t\t\t\t\tbody: bodyJson,\n\t\t\t\t\t\tsignal: options?.signal,\n\t\t\t\t\t});\n\t\t\t\t\tawait options?.onResponse?.(\n\t\t\t\t\t\t{ status: response.status, headers: headersToRecord(response.headers) },\n\t\t\t\t\t\tmodel,\n\t\t\t\t\t);\n\n\t\t\t\t\tif (response.ok) {\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\n\t\t\t\t\tconst errorText = await response.text();\n\t\t\t\t\tif (attempt < MAX_RETRIES && isRetryableError(response.status, errorText)) {\n\t\t\t\t\t\tconst delayMs = BASE_DELAY_MS * 2 ** attempt;\n\t\t\t\t\t\tawait sleep(delayMs, options?.signal);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\n\t\t\t\t\t// Parse error for friendly message on final attempt or non-retryable error\n\t\t\t\t\tconst fakeResponse = new Response(errorText, {\n\t\t\t\t\t\tstatus: response.status,\n\t\t\t\t\t\tstatusText: response.statusText,\n\t\t\t\t\t});\n\t\t\t\t\tconst info = await parseErrorResponse(fakeResponse);\n\t\t\t\t\tthrow new Error(info.friendlyMessage || info.message);\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (error instanceof Error) {\n\t\t\t\t\t\tif (error.name === \"AbortError\" || error.message === \"Request was aborted\") {\n\t\t\t\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tlastError = error instanceof Error ? error : new Error(String(error));\n\t\t\t\t\t// Network errors are retryable\n\t\t\t\t\tif (attempt < MAX_RETRIES && !lastError.message.includes(\"usage limit\")) {\n\t\t\t\t\t\tconst delayMs = BASE_DELAY_MS * 2 ** attempt;\n\t\t\t\t\t\tawait sleep(delayMs, options?.signal);\n\t\t\t\t\t\tcontinue;\n\t\t\t\t\t}\n\t\t\t\t\tthrow lastError;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!response?.ok) {\n\t\t\t\tthrow lastError ?? new Error(\"Failed after retries\");\n\t\t\t}\n\n\t\t\tif (!response.body) {\n\t\t\t\tthrow new Error(\"No response body\");\n\t\t\t}\n\n\t\t\tstream.push({ type: \"start\", partial: output });\n\t\t\tawait processStream(response, output, stream, model, options);\n\n\t\t\tif (options?.signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t}\n\n\t\t\tstream.push({ type: \"done\", reason: output.stopReason as \"stop\" | \"length\" | \"toolUse\", message: output });\n\t\t\tstream.end();\n\t\t} catch (error) {\n\t\t\tfor (const block of output.content) {\n\t\t\t\t// partialJson is only a streaming scratch buffer; never persist it.\n\t\t\t\tdelete (block as { partialJson?: string }).partialJson;\n\t\t\t}\n\t\t\toutput.stopReason = options?.signal?.aborted ? \"aborted\" : \"error\";\n\t\t\toutput.errorMessage = error instanceof Error ? error.message : String(error);\n\t\t\tstream.push({ type: \"error\", reason: output.stopReason, error: output });\n\t\t\tstream.end();\n\t\t}\n\t})();\n\n\treturn stream;\n};\n\nexport const streamSimpleOpenAICodexResponses: StreamFunction<\"openai-codex-responses\", SimpleStreamOptions> = (\n\tmodel: Model<\"openai-codex-responses\">,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream => {\n\tconst apiKey = options?.apiKey || getEnvApiKey(model.provider);\n\tif (!apiKey) {\n\t\tthrow new Error(`No API key for provider: ${model.provider}`);\n\t}\n\n\tconst base = buildBaseOptions(model, options, apiKey);\n\tconst reasoningEffort = supportsXhigh(model) ? options?.reasoning : clampReasoning(options?.reasoning);\n\n\treturn streamOpenAICodexResponses(model, context, {\n\t\t...base,\n\t\treasoningEffort,\n\t} satisfies OpenAICodexResponsesOptions);\n};\n\n// ============================================================================\n// Request Building\n// ============================================================================\n\nfunction buildRequestBody(\n\tmodel: Model<\"openai-codex-responses\">,\n\tcontext: Context,\n\toptions?: OpenAICodexResponsesOptions,\n): RequestBody {\n\tconst messages = convertResponsesMessages(model, context, CODEX_TOOL_CALL_PROVIDERS, {\n\t\tincludeSystemPrompt: false,\n\t});\n\n\tconst body: RequestBody = {\n\t\tmodel: model.id,\n\t\tstore: false,\n\t\tstream: true,\n\t\tinstructions: context.systemPrompt,\n\t\tinput: messages,\n\t\ttext: { verbosity: options?.textVerbosity || \"medium\" },\n\t\tinclude: [\"reasoning.encrypted_content\"],\n\t\tprompt_cache_key: options?.sessionId,\n\t\ttool_choice: \"auto\",\n\t\tparallel_tool_calls: true,\n\t};\n\n\tif (options?.temperature !== undefined) {\n\t\tbody.temperature = options.temperature;\n\t}\n\n\tif (options?.serviceTier !== undefined) {\n\t\tbody.service_tier = options.serviceTier;\n\t}\n\n\tif (context.tools) {\n\t\tbody.tools = convertResponsesTools(context.tools, { strict: null });\n\t}\n\n\tif (options?.reasoningEffort !== undefined) {\n\t\tbody.reasoning = {\n\t\t\teffort: clampReasoningEffort(model.id, options.reasoningEffort),\n\t\t\tsummary: options.reasoningSummary ?? \"auto\",\n\t\t};\n\t}\n\n\treturn body;\n}\n\nfunction clampReasoningEffort(modelId: string, effort: string): string {\n\tconst id = modelId.includes(\"/\") ? modelId.split(\"/\").pop()! : modelId;\n\tif (\n\t\t(id.startsWith(\"gpt-5.2\") || id.startsWith(\"gpt-5.3\") || id.startsWith(\"gpt-5.4\") || id.startsWith(\"gpt-5.5\")) &&\n\t\teffort === \"minimal\"\n\t)\n\t\treturn \"low\";\n\tif (id === \"gpt-5.1\" && effort === \"xhigh\") return \"high\";\n\tif (id === \"gpt-5.1-codex-mini\") return effort === \"high\" || effort === \"xhigh\" ? \"high\" : \"medium\";\n\treturn effort;\n}\n\nfunction getServiceTierCostMultiplier(\n\tmodel: Pick<Model<\"openai-codex-responses\">, \"id\">,\n\tserviceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n): number {\n\tswitch (serviceTier) {\n\t\tcase \"flex\":\n\t\t\treturn 0.5;\n\t\tcase \"priority\":\n\t\t\treturn model.id === \"gpt-5.5\" ? 2.5 : 2;\n\t\tdefault:\n\t\t\treturn 1;\n\t}\n}\n\nfunction applyServiceTierPricing(\n\tusage: Usage,\n\tserviceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n\tmodel: Pick<Model<\"openai-codex-responses\">, \"id\">,\n) {\n\tconst multiplier = getServiceTierCostMultiplier(model, serviceTier);\n\tif (multiplier === 1) return;\n\n\tusage.cost.input *= multiplier;\n\tusage.cost.output *= multiplier;\n\tusage.cost.cacheRead *= multiplier;\n\tusage.cost.cacheWrite *= multiplier;\n\tusage.cost.total = usage.cost.input + usage.cost.output + usage.cost.cacheRead + usage.cost.cacheWrite;\n}\n\nfunction resolveCodexServiceTier(\n\tresponseServiceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n\trequestServiceTier: ResponseCreateParamsStreaming[\"service_tier\"] | undefined,\n): ResponseCreateParamsStreaming[\"service_tier\"] | undefined {\n\tif (responseServiceTier === \"default\" && (requestServiceTier === \"flex\" || requestServiceTier === \"priority\")) {\n\t\treturn requestServiceTier;\n\t}\n\treturn responseServiceTier ?? requestServiceTier;\n}\n\nfunction resolveCodexUrl(baseUrl?: string): string {\n\tconst raw = baseUrl && baseUrl.trim().length > 0 ? baseUrl : DEFAULT_CODEX_BASE_URL;\n\tconst normalized = raw.replace(/\\/+$/, \"\");\n\tif (normalized.endsWith(\"/codex/responses\")) return normalized;\n\tif (normalized.endsWith(\"/codex\")) return `${normalized}/responses`;\n\treturn `${normalized}/codex/responses`;\n}\n\nfunction resolveCodexWebSocketUrl(baseUrl?: string): string {\n\tconst url = new URL(resolveCodexUrl(baseUrl));\n\tif (url.protocol === \"https:\") url.protocol = \"wss:\";\n\tif (url.protocol === \"http:\") url.protocol = \"ws:\";\n\treturn url.toString();\n}\n\n// ============================================================================\n// Response Processing\n// ============================================================================\n\nasync function processStream(\n\tresponse: Response,\n\toutput: AssistantMessage,\n\tstream: AssistantMessageEventStream,\n\tmodel: Model<\"openai-codex-responses\">,\n\toptions?: OpenAICodexResponsesOptions,\n): Promise<void> {\n\tawait processResponsesStream(mapCodexEvents(parseSSE(response)), output, stream, model, {\n\t\tserviceTier: options?.serviceTier,\n\t\tresolveServiceTier: resolveCodexServiceTier,\n\t\tapplyServiceTierPricing: (usage, serviceTier) => applyServiceTierPricing(usage, serviceTier, model),\n\t});\n}\n\nasync function* mapCodexEvents(events: AsyncIterable<Record<string, unknown>>): AsyncGenerator<ResponseStreamEvent> {\n\tfor await (const event of events) {\n\t\tconst type = typeof event.type === \"string\" ? event.type : undefined;\n\t\tif (!type) continue;\n\n\t\tif (type === \"error\") {\n\t\t\tconst code = (event as { code?: string }).code || \"\";\n\t\t\tconst message = (event as { message?: string }).message || \"\";\n\t\t\tthrow new Error(`Codex error: ${message || code || JSON.stringify(event)}`);\n\t\t}\n\n\t\tif (type === \"response.failed\") {\n\t\t\tconst msg = (event as { response?: { error?: { message?: string } } }).response?.error?.message;\n\t\t\tthrow new Error(msg || \"Codex response failed\");\n\t\t}\n\n\t\tif (type === \"response.done\" || type === \"response.completed\" || type === \"response.incomplete\") {\n\t\t\tconst response = (event as { response?: { status?: unknown } }).response;\n\t\t\tconst normalizedResponse = response\n\t\t\t\t? { ...response, status: normalizeCodexStatus(response.status) }\n\t\t\t\t: response;\n\t\t\tyield { ...event, type: \"response.completed\", response: normalizedResponse } as ResponseStreamEvent;\n\t\t\treturn;\n\t\t}\n\n\t\tyield event as unknown as ResponseStreamEvent;\n\t}\n}\n\nfunction normalizeCodexStatus(status: unknown): CodexResponseStatus | undefined {\n\tif (typeof status !== \"string\") return undefined;\n\treturn CODEX_RESPONSE_STATUSES.has(status as CodexResponseStatus) ? (status as CodexResponseStatus) : undefined;\n}\n\n// ============================================================================\n// SSE Parsing\n// ============================================================================\n\nasync function* parseSSE(response: Response): AsyncGenerator<Record<string, unknown>> {\n\tif (!response.body) return;\n\n\tconst reader = response.body.getReader();\n\tconst decoder = new TextDecoder();\n\tlet buffer = \"\";\n\n\ttry {\n\t\twhile (true) {\n\t\t\tconst { done, value } = await reader.read();\n\t\t\tif (done) break;\n\t\t\tbuffer += decoder.decode(value, { stream: true });\n\n\t\t\tlet idx = buffer.indexOf(\"\\n\\n\");\n\t\t\twhile (idx !== -1) {\n\t\t\t\tconst chunk = buffer.slice(0, idx);\n\t\t\t\tbuffer = buffer.slice(idx + 2);\n\n\t\t\t\tconst dataLines = chunk\n\t\t\t\t\t.split(\"\\n\")\n\t\t\t\t\t.filter((l) => l.startsWith(\"data:\"))\n\t\t\t\t\t.map((l) => l.slice(5).trim());\n\t\t\t\tif (dataLines.length > 0) {\n\t\t\t\t\tconst data = dataLines.join(\"\\n\").trim();\n\t\t\t\t\tif (data && data !== \"[DONE]\") {\n\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\tyield JSON.parse(data);\n\t\t\t\t\t\t} catch {}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tidx = buffer.indexOf(\"\\n\\n\");\n\t\t\t}\n\t\t}\n\t} finally {\n\t\ttry {\n\t\t\tawait reader.cancel();\n\t\t} catch {}\n\t\ttry {\n\t\t\treader.releaseLock();\n\t\t} catch {}\n\t}\n}\n\n// ============================================================================\n// WebSocket Parsing\n// ============================================================================\n\nconst OPENAI_BETA_RESPONSES_WEBSOCKETS = \"responses_websockets=2026-02-06\";\nconst SESSION_WEBSOCKET_CACHE_TTL_MS = 5 * 60 * 1000;\n\ntype WebSocketEventType = \"open\" | \"message\" | \"error\" | \"close\";\ntype WebSocketListener = (event: unknown) => void;\n\ninterface WebSocketLike {\n\tclose(code?: number, reason?: string): void;\n\tsend(data: string): void;\n\taddEventListener(type: WebSocketEventType, listener: WebSocketListener): void;\n\tremoveEventListener(type: WebSocketEventType, listener: WebSocketListener): void;\n}\n\ninterface CachedWebSocketConnection {\n\tsocket: WebSocketLike;\n\tbusy: boolean;\n\tidleTimer?: ReturnType<typeof setTimeout>;\n}\n\nconst websocketSessionCache = new Map<string, CachedWebSocketConnection>();\n\ntype WebSocketConstructor = new (\n\turl: string,\n\tprotocols?: string | string[] | { headers?: Record<string, string> },\n) => WebSocketLike;\n\nfunction getWebSocketConstructor(): WebSocketConstructor | null {\n\tconst ctor = (globalThis as { WebSocket?: unknown }).WebSocket;\n\tif (typeof ctor !== \"function\") return null;\n\treturn ctor as unknown as WebSocketConstructor;\n}\n\nfunction getWebSocketReadyState(socket: WebSocketLike): number | undefined {\n\tconst readyState = (socket as { readyState?: unknown }).readyState;\n\treturn typeof readyState === \"number\" ? readyState : undefined;\n}\n\nfunction isWebSocketReusable(socket: WebSocketLike): boolean {\n\tconst readyState = getWebSocketReadyState(socket);\n\t// If readyState is unavailable, assume the runtime keeps it open/reusable.\n\treturn readyState === undefined || readyState === 1;\n}\n\nfunction closeWebSocketSilently(socket: WebSocketLike, code = 1000, reason = \"done\"): void {\n\ttry {\n\t\tsocket.close(code, reason);\n\t} catch {}\n}\n\nfunction scheduleSessionWebSocketExpiry(sessionId: string, entry: CachedWebSocketConnection): void {\n\tif (entry.idleTimer) {\n\t\tclearTimeout(entry.idleTimer);\n\t}\n\tentry.idleTimer = setTimeout(() => {\n\t\tif (entry.busy) return;\n\t\tcloseWebSocketSilently(entry.socket, 1000, \"idle_timeout\");\n\t\twebsocketSessionCache.delete(sessionId);\n\t}, SESSION_WEBSOCKET_CACHE_TTL_MS);\n}\n\nasync function connectWebSocket(url: string, headers: Headers, signal?: AbortSignal): Promise<WebSocketLike> {\n\tconst WebSocketCtor = getWebSocketConstructor();\n\tif (!WebSocketCtor) {\n\t\tthrow new Error(\"WebSocket transport is not available in this runtime\");\n\t}\n\n\tconst wsHeaders = headersToRecord(headers);\n\tdelete wsHeaders[\"OpenAI-Beta\"];\n\n\treturn new Promise<WebSocketLike>((resolve, reject) => {\n\t\tlet settled = false;\n\t\tlet socket: WebSocketLike;\n\n\t\ttry {\n\t\t\tsocket = new WebSocketCtor(url, { headers: wsHeaders });\n\t\t} catch (error) {\n\t\t\treject(error instanceof Error ? error : new Error(String(error)));\n\t\t\treturn;\n\t\t}\n\n\t\tconst onOpen: WebSocketListener = () => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tcleanup();\n\t\t\tresolve(socket);\n\t\t};\n\t\tconst onError: WebSocketListener = (event) => {\n\t\t\tconst error = extractWebSocketError(event);\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tcleanup();\n\t\t\treject(error);\n\t\t};\n\t\tconst onClose: WebSocketListener = (event) => {\n\t\t\tconst error = extractWebSocketCloseError(event);\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tcleanup();\n\t\t\treject(error);\n\t\t};\n\t\tconst onAbort = () => {\n\t\t\tif (settled) return;\n\t\t\tsettled = true;\n\t\t\tcleanup();\n\t\t\tsocket.close(1000, \"aborted\");\n\t\t\treject(new Error(\"Request was aborted\"));\n\t\t};\n\n\t\tconst cleanup = () => {\n\t\t\tsocket.removeEventListener(\"open\", onOpen);\n\t\t\tsocket.removeEventListener(\"error\", onError);\n\t\t\tsocket.removeEventListener(\"close\", onClose);\n\t\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t\t};\n\n\t\tsocket.addEventListener(\"open\", onOpen);\n\t\tsocket.addEventListener(\"error\", onError);\n\t\tsocket.addEventListener(\"close\", onClose);\n\t\tsignal?.addEventListener(\"abort\", onAbort);\n\t});\n}\n\nasync function acquireWebSocket(\n\turl: string,\n\theaders: Headers,\n\tsessionId: string | undefined,\n\tsignal?: AbortSignal,\n): Promise<{ socket: WebSocketLike; release: (options?: { keep?: boolean }) => void }> {\n\tif (!sessionId) {\n\t\tconst socket = await connectWebSocket(url, headers, signal);\n\t\treturn {\n\t\t\tsocket,\n\t\t\trelease: ({ keep } = {}) => {\n\t\t\t\tif (keep === false) {\n\t\t\t\t\tcloseWebSocketSilently(socket);\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tcloseWebSocketSilently(socket);\n\t\t\t},\n\t\t};\n\t}\n\n\tconst cached = websocketSessionCache.get(sessionId);\n\tif (cached) {\n\t\tif (cached.idleTimer) {\n\t\t\tclearTimeout(cached.idleTimer);\n\t\t\tcached.idleTimer = undefined;\n\t\t}\n\t\tif (!cached.busy && isWebSocketReusable(cached.socket)) {\n\t\t\tcached.busy = true;\n\t\t\treturn {\n\t\t\t\tsocket: cached.socket,\n\t\t\t\trelease: ({ keep } = {}) => {\n\t\t\t\t\tif (!keep || !isWebSocketReusable(cached.socket)) {\n\t\t\t\t\t\tcloseWebSocketSilently(cached.socket);\n\t\t\t\t\t\twebsocketSessionCache.delete(sessionId);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tcached.busy = false;\n\t\t\t\t\tscheduleSessionWebSocketExpiry(sessionId, cached);\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tif (cached.busy) {\n\t\t\tconst socket = await connectWebSocket(url, headers, signal);\n\t\t\treturn {\n\t\t\t\tsocket,\n\t\t\t\trelease: () => {\n\t\t\t\t\tcloseWebSocketSilently(socket);\n\t\t\t\t},\n\t\t\t};\n\t\t}\n\t\tif (!isWebSocketReusable(cached.socket)) {\n\t\t\tcloseWebSocketSilently(cached.socket);\n\t\t\twebsocketSessionCache.delete(sessionId);\n\t\t}\n\t}\n\n\tconst socket = await connectWebSocket(url, headers, signal);\n\tconst entry: CachedWebSocketConnection = { socket, busy: true };\n\twebsocketSessionCache.set(sessionId, entry);\n\treturn {\n\t\tsocket,\n\t\trelease: ({ keep } = {}) => {\n\t\t\tif (!keep || !isWebSocketReusable(entry.socket)) {\n\t\t\t\tcloseWebSocketSilently(entry.socket);\n\t\t\t\tif (entry.idleTimer) clearTimeout(entry.idleTimer);\n\t\t\t\tif (websocketSessionCache.get(sessionId) === entry) {\n\t\t\t\t\twebsocketSessionCache.delete(sessionId);\n\t\t\t\t}\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tentry.busy = false;\n\t\t\tscheduleSessionWebSocketExpiry(sessionId, entry);\n\t\t},\n\t};\n}\n\nfunction extractWebSocketError(event: unknown): Error {\n\tif (event && typeof event === \"object\" && \"message\" in event) {\n\t\tconst message = (event as { message?: unknown }).message;\n\t\tif (typeof message === \"string\" && message.length > 0) {\n\t\t\treturn new Error(message);\n\t\t}\n\t}\n\treturn new Error(\"WebSocket error\");\n}\n\nfunction extractWebSocketCloseError(event: unknown): Error {\n\tif (event && typeof event === \"object\") {\n\t\tconst code = \"code\" in event ? (event as { code?: unknown }).code : undefined;\n\t\tconst reason = \"reason\" in event ? (event as { reason?: unknown }).reason : undefined;\n\t\tconst codeText = typeof code === \"number\" ? ` ${code}` : \"\";\n\t\tconst reasonText = typeof reason === \"string\" && reason.length > 0 ? ` ${reason}` : \"\";\n\t\treturn new Error(`WebSocket closed${codeText}${reasonText}`.trim());\n\t}\n\treturn new Error(\"WebSocket closed\");\n}\n\nasync function decodeWebSocketData(data: unknown): Promise<string | null> {\n\tif (typeof data === \"string\") return data;\n\tif (data instanceof ArrayBuffer) {\n\t\treturn new TextDecoder().decode(new Uint8Array(data));\n\t}\n\tif (ArrayBuffer.isView(data)) {\n\t\tconst view = data as ArrayBufferView;\n\t\treturn new TextDecoder().decode(new Uint8Array(view.buffer, view.byteOffset, view.byteLength));\n\t}\n\tif (data && typeof data === \"object\" && \"arrayBuffer\" in data) {\n\t\tconst blobLike = data as { arrayBuffer: () => Promise<ArrayBuffer> };\n\t\tconst arrayBuffer = await blobLike.arrayBuffer();\n\t\treturn new TextDecoder().decode(new Uint8Array(arrayBuffer));\n\t}\n\treturn null;\n}\n\nasync function* parseWebSocket(socket: WebSocketLike, signal?: AbortSignal): AsyncGenerator<Record<string, unknown>> {\n\tconst queue: Record<string, unknown>[] = [];\n\tlet pending: (() => void) | null = null;\n\tlet done = false;\n\tlet failed: Error | null = null;\n\tlet sawCompletion = false;\n\n\tconst wake = () => {\n\t\tif (!pending) return;\n\t\tconst resolve = pending;\n\t\tpending = null;\n\t\tresolve();\n\t};\n\n\tconst onMessage: WebSocketListener = (event) => {\n\t\tvoid (async () => {\n\t\t\tif (!event || typeof event !== \"object\" || !(\"data\" in event)) return;\n\t\t\tconst text = await decodeWebSocketData((event as { data?: unknown }).data);\n\t\t\tif (!text) return;\n\t\t\ttry {\n\t\t\t\tconst parsed = JSON.parse(text) as Record<string, unknown>;\n\t\t\t\tconst type = typeof parsed.type === \"string\" ? parsed.type : \"\";\n\t\t\t\tif (type === \"response.completed\" || type === \"response.done\" || type === \"response.incomplete\") {\n\t\t\t\t\tsawCompletion = true;\n\t\t\t\t\tdone = true;\n\t\t\t\t}\n\t\t\t\tqueue.push(parsed);\n\t\t\t\twake();\n\t\t\t} catch {}\n\t\t})();\n\t};\n\n\tconst onError: WebSocketListener = (event) => {\n\t\tfailed = extractWebSocketError(event);\n\t\tdone = true;\n\t\twake();\n\t};\n\n\tconst onClose: WebSocketListener = (event) => {\n\t\tif (sawCompletion) {\n\t\t\tdone = true;\n\t\t\twake();\n\t\t\treturn;\n\t\t}\n\t\tif (!failed) {\n\t\t\tfailed = extractWebSocketCloseError(event);\n\t\t}\n\t\tdone = true;\n\t\twake();\n\t};\n\n\tconst onAbort = () => {\n\t\tfailed = new Error(\"Request was aborted\");\n\t\tdone = true;\n\t\twake();\n\t};\n\n\tsocket.addEventListener(\"message\", onMessage);\n\tsocket.addEventListener(\"error\", onError);\n\tsocket.addEventListener(\"close\", onClose);\n\tsignal?.addEventListener(\"abort\", onAbort);\n\n\ttry {\n\t\twhile (true) {\n\t\t\tif (signal?.aborted) {\n\t\t\t\tthrow new Error(\"Request was aborted\");\n\t\t\t}\n\t\t\tif (queue.length > 0) {\n\t\t\t\tyield queue.shift()!;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (done) break;\n\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\tpending = resolve;\n\t\t\t});\n\t\t}\n\n\t\tif (failed) {\n\t\t\tthrow failed;\n\t\t}\n\t\tif (!sawCompletion) {\n\t\t\tthrow new Error(\"WebSocket stream closed before response.completed\");\n\t\t}\n\t} finally {\n\t\tsocket.removeEventListener(\"message\", onMessage);\n\t\tsocket.removeEventListener(\"error\", onError);\n\t\tsocket.removeEventListener(\"close\", onClose);\n\t\tsignal?.removeEventListener(\"abort\", onAbort);\n\t}\n}\n\nasync function processWebSocketStream(\n\turl: string,\n\tbody: RequestBody,\n\theaders: Headers,\n\toutput: AssistantMessage,\n\tstream: AssistantMessageEventStream,\n\tmodel: Model<\"openai-codex-responses\">,\n\tonStart: () => void,\n\toptions?: OpenAICodexResponsesOptions,\n): Promise<void> {\n\tconst { socket, release } = await acquireWebSocket(url, headers, options?.sessionId, options?.signal);\n\tlet keepConnection = true;\n\ttry {\n\t\tsocket.send(JSON.stringify({ type: \"response.create\", ...body }));\n\t\tonStart();\n\t\tstream.push({ type: \"start\", partial: output });\n\t\tawait processResponsesStream(mapCodexEvents(parseWebSocket(socket, options?.signal)), output, stream, model, {\n\t\t\tserviceTier: options?.serviceTier,\n\t\t\tresolveServiceTier: resolveCodexServiceTier,\n\t\t\tapplyServiceTierPricing: (usage, serviceTier) => applyServiceTierPricing(usage, serviceTier, model),\n\t\t});\n\t\tif (options?.signal?.aborted) {\n\t\t\tkeepConnection = false;\n\t\t}\n\t} catch (error) {\n\t\tkeepConnection = false;\n\t\tthrow error;\n\t} finally {\n\t\trelease({ keep: keepConnection });\n\t}\n}\n\n// ============================================================================\n// Error Handling\n// ============================================================================\n\nasync function parseErrorResponse(response: Response): Promise<{ message: string; friendlyMessage?: string }> {\n\tconst raw = await response.text();\n\tlet message = raw || response.statusText || \"Request failed\";\n\tlet friendlyMessage: string | undefined;\n\n\ttry {\n\t\tconst parsed = JSON.parse(raw) as {\n\t\t\terror?: { code?: string; type?: string; message?: string; plan_type?: string; resets_at?: number };\n\t\t};\n\t\tconst err = parsed?.error;\n\t\tif (err) {\n\t\t\tconst code = err.code || err.type || \"\";\n\t\t\tif (/usage_limit_reached|usage_not_included|rate_limit_exceeded/i.test(code) || response.status === 429) {\n\t\t\t\tconst plan = err.plan_type ? ` (${err.plan_type.toLowerCase()} plan)` : \"\";\n\t\t\t\tconst mins = err.resets_at\n\t\t\t\t\t? Math.max(0, Math.round((err.resets_at * 1000 - Date.now()) / 60000))\n\t\t\t\t\t: undefined;\n\t\t\t\tconst when = mins !== undefined ? ` Try again in ~${mins} min.` : \"\";\n\t\t\t\tfriendlyMessage = `You have hit your ChatGPT usage limit${plan}.${when}`.trim();\n\t\t\t}\n\t\t\tmessage = err.message || friendlyMessage || message;\n\t\t}\n\t} catch {}\n\n\treturn { message, friendlyMessage };\n}\n\n// ============================================================================\n// Auth & Headers\n// ============================================================================\n\nfunction extractAccountId(token: string): string {\n\ttry {\n\t\tconst parts = token.split(\".\");\n\t\tif (parts.length !== 3) throw new Error(\"Invalid token\");\n\t\tconst payload = JSON.parse(atob(parts[1]));\n\t\tconst accountId = payload?.[JWT_CLAIM_PATH]?.chatgpt_account_id;\n\t\tif (!accountId) throw new Error(\"No account ID in token\");\n\t\treturn accountId;\n\t} catch {\n\t\tthrow new Error(\"Failed to extract accountId from token\");\n\t}\n}\n\nfunction createCodexRequestId(): string {\n\tif (typeof globalThis.crypto?.randomUUID === \"function\") {\n\t\treturn globalThis.crypto.randomUUID();\n\t}\n\treturn `codex_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;\n}\n\nfunction buildBaseCodexHeaders(\n\tinitHeaders: Record<string, string> | undefined,\n\tadditionalHeaders: Record<string, string> | undefined,\n\taccountId: string,\n\ttoken: string,\n): Headers {\n\tconst headers = new Headers(initHeaders);\n\tfor (const [key, value] of Object.entries(additionalHeaders || {})) {\n\t\theaders.set(key, value);\n\t}\n\theaders.set(\"Authorization\", `Bearer ${token}`);\n\theaders.set(\"chatgpt-account-id\", accountId);\n\theaders.set(\"originator\", \"pi\");\n\tconst userAgent = _os ? `pi (${_os.platform()} ${_os.release()}; ${_os.arch()})` : \"pi (browser)\";\n\theaders.set(\"User-Agent\", userAgent);\n\treturn headers;\n}\n\nfunction buildSSEHeaders(\n\tinitHeaders: Record<string, string> | undefined,\n\tadditionalHeaders: Record<string, string> | undefined,\n\taccountId: string,\n\ttoken: string,\n\tsessionId?: string,\n): Headers {\n\tconst headers = buildBaseCodexHeaders(initHeaders, additionalHeaders, accountId, token);\n\theaders.set(\"OpenAI-Beta\", \"responses=experimental\");\n\theaders.set(\"accept\", \"text/event-stream\");\n\theaders.set(\"content-type\", \"application/json\");\n\n\tif (sessionId) {\n\t\theaders.set(\"session_id\", sessionId);\n\t\theaders.set(\"x-client-request-id\", sessionId);\n\t}\n\n\treturn headers;\n}\n\nfunction buildWebSocketHeaders(\n\tinitHeaders: Record<string, string> | undefined,\n\tadditionalHeaders: Record<string, string> | undefined,\n\taccountId: string,\n\ttoken: string,\n\trequestId: string,\n): Headers {\n\tconst headers = buildBaseCodexHeaders(initHeaders, additionalHeaders, accountId, token);\n\theaders.delete(\"accept\");\n\theaders.delete(\"content-type\");\n\theaders.delete(\"OpenAI-Beta\");\n\theaders.delete(\"openai-beta\");\n\theaders.set(\"OpenAI-Beta\", OPENAI_BETA_RESPONSES_WEBSOCKETS);\n\theaders.set(\"x-client-request-id\", requestId);\n\theaders.set(\"session_id\", requestId);\n\treturn headers;\n}\n"]}
@@ -238,7 +238,8 @@ function buildRequestBody(model, context, options) {
238
238
  }
239
239
  function clampReasoningEffort(modelId, effort) {
240
240
  const id = modelId.includes("/") ? modelId.split("/").pop() : modelId;
241
- if ((id.startsWith("gpt-5.2") || id.startsWith("gpt-5.3") || id.startsWith("gpt-5.4")) && effort === "minimal")
241
+ if ((id.startsWith("gpt-5.2") || id.startsWith("gpt-5.3") || id.startsWith("gpt-5.4") || id.startsWith("gpt-5.5")) &&
242
+ effort === "minimal")
242
243
  return "low";
243
244
  if (id === "gpt-5.1" && effort === "xhigh")
244
245
  return "high";
@@ -246,18 +247,18 @@ function clampReasoningEffort(modelId, effort) {
246
247
  return effort === "high" || effort === "xhigh" ? "high" : "medium";
247
248
  return effort;
248
249
  }
249
- function getServiceTierCostMultiplier(serviceTier) {
250
+ function getServiceTierCostMultiplier(model, serviceTier) {
250
251
  switch (serviceTier) {
251
252
  case "flex":
252
253
  return 0.5;
253
254
  case "priority":
254
- return 2;
255
+ return model.id === "gpt-5.5" ? 2.5 : 2;
255
256
  default:
256
257
  return 1;
257
258
  }
258
259
  }
259
- function applyServiceTierPricing(usage, serviceTier) {
260
- const multiplier = getServiceTierCostMultiplier(serviceTier);
260
+ function applyServiceTierPricing(usage, serviceTier, model) {
261
+ const multiplier = getServiceTierCostMultiplier(model, serviceTier);
261
262
  if (multiplier === 1)
262
263
  return;
263
264
  usage.cost.input *= multiplier;
@@ -296,7 +297,7 @@ async function processStream(response, output, stream, model, options) {
296
297
  await processResponsesStream(mapCodexEvents(parseSSE(response)), output, stream, model, {
297
298
  serviceTier: options?.serviceTier,
298
299
  resolveServiceTier: resolveCodexServiceTier,
299
- applyServiceTierPricing,
300
+ applyServiceTierPricing: (usage, serviceTier) => applyServiceTierPricing(usage, serviceTier, model),
300
301
  });
301
302
  }
302
303
  async function* mapCodexEvents(events) {
@@ -677,7 +678,7 @@ async function processWebSocketStream(url, body, headers, output, stream, model,
677
678
  await processResponsesStream(mapCodexEvents(parseWebSocket(socket, options?.signal)), output, stream, model, {
678
679
  serviceTier: options?.serviceTier,
679
680
  resolveServiceTier: resolveCodexServiceTier,
680
- applyServiceTierPricing,
681
+ applyServiceTierPricing: (usage, serviceTier) => applyServiceTierPricing(usage, serviceTier, model),
681
682
  });
682
683
  if (options?.signal?.aborted) {
683
684
  keepConnection = false;