@opengeni/codex 6.8.0 → 6.9.1-canary.41937124785001

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -3234,7 +3234,9 @@ function boundedErrorMessage(body) {
3234
3234
  // src/realtime.ts
3235
3235
  var MAX_REALTIME_SDP_BYTES = 1024 * 1024;
3236
3236
  var MAX_REALTIME_PROVIDER_VALUE_LENGTH = 128;
3237
+ var MAX_REALTIME_ERROR_BODY_BYTES = 16 * 1024;
3237
3238
  var REALTIME_PROVIDER_VALUE = /^[a-z0-9][a-z0-9._-]*$/i;
3239
+ var REALTIME_PROVIDER_ERROR_TOKEN = /^[A-Za-z0-9][A-Za-z0-9 _.:-]{0,63}$/;
3238
3240
  var REALTIME_CALL_ID = /^(?:rtc_.+|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i;
3239
3241
  var CODEX_REALTIME_VOICES = [
3240
3242
  "juniper",
@@ -3248,17 +3250,19 @@ var CODEX_REALTIME_VOICES = [
3248
3250
  "cove"
3249
3251
  ];
3250
3252
  var CodexRealtimeError = class extends Error {
3251
- constructor(code, message, providerStatus = null) {
3253
+ constructor(code, message, providerStatus = null, diagnostics = { stage: "request" }) {
3252
3254
  super(message);
3253
3255
  this.code = code;
3254
3256
  this.providerStatus = providerStatus;
3257
+ this.diagnostics = diagnostics;
3255
3258
  this.name = "CodexRealtimeError";
3256
3259
  }
3257
3260
  };
3258
3261
  var FALLBACK_REALTIME_PROVIDER_CONFIG = {
3259
3262
  architecture: CODEX_REALTIME_PROVIDER_ARCHITECTURE_FALLBACK,
3260
3263
  model: CODEX_REALTIME_PROVIDER_MODEL_FALLBACK,
3261
- version: CODEX_REALTIME_VERSION
3264
+ version: CODEX_REALTIME_VERSION,
3265
+ source: "fallback"
3262
3266
  };
3263
3267
  async function fetchCodexRealtimeProviderConfig(auth, fetchImpl = fetch, options = {}) {
3264
3268
  if (options.signal?.aborted) {
@@ -3294,7 +3298,8 @@ async function fetchCodexRealtimeProviderConfig(auth, fetchImpl = fetch, options
3294
3298
  throw new CodexRealtimeError(
3295
3299
  "authentication",
3296
3300
  "Codex subscription rejected authentication",
3297
- response.status
3301
+ response.status,
3302
+ { stage: "config" }
3298
3303
  );
3299
3304
  }
3300
3305
  if (!response.ok) {
@@ -3307,18 +3312,26 @@ async function fetchCodexRealtimeProviderConfig(auth, fetchImpl = fetch, options
3307
3312
  const value = payload.dynamic_configs?.[CODEX_REALTIME_CONFIG_ID]?.value;
3308
3313
  const version = value?.version;
3309
3314
  if (version !== void 0 && version !== CODEX_REALTIME_VERSION) {
3310
- throw new CodexRealtimeError(
3311
- "incompatible",
3312
- `Codex realtime remote configuration requires ${String(version)}`
3313
- );
3315
+ return {
3316
+ ...FALLBACK_REALTIME_PROVIDER_CONFIG,
3317
+ ...validProviderValue(version) ? { advertisedVersion: version } : {}
3318
+ };
3314
3319
  }
3315
3320
  const architecture = validProviderValue(value?.architecture) ? value.architecture : FALLBACK_REALTIME_PROVIDER_CONFIG.architecture;
3316
3321
  const model = validProviderValue(value?.model) ? value.model : FALLBACK_REALTIME_PROVIDER_CONFIG.model;
3317
- return { architecture, model, version: CODEX_REALTIME_VERSION };
3322
+ return {
3323
+ architecture,
3324
+ model,
3325
+ version: CODEX_REALTIME_VERSION,
3326
+ source: value ? "remote" : "fallback",
3327
+ ...version === void 0 ? {} : { advertisedVersion: CODEX_REALTIME_VERSION }
3328
+ };
3318
3329
  } catch (error) {
3319
3330
  if (error instanceof CodexRealtimeError) throw error;
3320
3331
  if (options.signal?.aborted) {
3321
- throw new CodexRealtimeError("cancelled", "Codex realtime request cancelled");
3332
+ throw new CodexRealtimeError("cancelled", "Codex realtime request cancelled", null, {
3333
+ stage: "config"
3334
+ });
3322
3335
  }
3323
3336
  return FALLBACK_REALTIME_PROVIDER_CONFIG;
3324
3337
  } finally {
@@ -3330,6 +3343,13 @@ async function createCodexRealtimeCall(auth, input, fetchImpl = fetch, options =
3330
3343
  validateRealtimeInput(input);
3331
3344
  const timeoutMs = options.timeoutMs ?? CODEX_REALTIME_CALL_TIMEOUT_MS;
3332
3345
  const providerConfig = options.providerConfig ?? FALLBACK_REALTIME_PROVIDER_CONFIG;
3346
+ const callDiagnostics = {
3347
+ stage: "call",
3348
+ configSource: providerConfig.source,
3349
+ advertisedVersion: validProviderValue(providerConfig.advertisedVersion) ? providerConfig.advertisedVersion : void 0,
3350
+ providerModel: validProviderValue(providerConfig.model) ? providerConfig.model : void 0,
3351
+ providerArchitecture: validProviderValue(providerConfig.architecture) ? providerConfig.architecture : void 0
3352
+ };
3333
3353
  if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
3334
3354
  throw new CodexRealtimeError("invalid_request", "Codex realtime timeout must be positive");
3335
3355
  }
@@ -3357,14 +3377,28 @@ async function createCodexRealtimeCall(auth, input, fetchImpl = fetch, options =
3357
3377
  });
3358
3378
  const onAbort = () => {
3359
3379
  controller.abort(options.signal?.reason);
3360
- rejectCancellation?.(new CodexRealtimeError("cancelled", "Codex realtime request cancelled"));
3380
+ rejectCancellation?.(
3381
+ new CodexRealtimeError(
3382
+ "cancelled",
3383
+ "Codex realtime request cancelled",
3384
+ null,
3385
+ callDiagnostics
3386
+ )
3387
+ );
3361
3388
  };
3362
3389
  options.signal?.addEventListener("abort", onAbort, { once: true });
3363
3390
  const deadline = new Promise((_resolve, reject) => {
3364
3391
  timeout = setTimeout(() => {
3365
3392
  timedOut = true;
3366
3393
  controller.abort();
3367
- reject(new CodexRealtimeError("timeout", "Codex realtime request timed out"));
3394
+ reject(
3395
+ new CodexRealtimeError(
3396
+ "timeout",
3397
+ "Codex realtime request timed out",
3398
+ null,
3399
+ callDiagnostics
3400
+ )
3401
+ );
3368
3402
  }, timeoutMs);
3369
3403
  });
3370
3404
  const request = (async () => {
@@ -3406,8 +3440,8 @@ async function createCodexRealtimeCall(auth, input, fetchImpl = fetch, options =
3406
3440
  }
3407
3441
  );
3408
3442
  if (!response.ok) {
3409
- await response.body?.cancel().catch(() => void 0);
3410
- throw providerHttpError(response.status);
3443
+ const providerError = await readProviderErrorFields(response);
3444
+ throw providerHttpError(response.status, { ...callDiagnostics, ...providerError });
3411
3445
  }
3412
3446
  const location = response.headers.get("location");
3413
3447
  if (!location || !validRealtimeLocation(location)) {
@@ -3415,15 +3449,17 @@ async function createCodexRealtimeCall(auth, input, fetchImpl = fetch, options =
3415
3449
  throw new CodexRealtimeError(
3416
3450
  "invalid_response",
3417
3451
  "Codex realtime response did not identify a compatible call",
3418
- response.status
3452
+ response.status,
3453
+ callDiagnostics
3419
3454
  );
3420
3455
  }
3421
- const sdp = await readBoundedSdp(response);
3456
+ const sdp = await readBoundedSdp(response, callDiagnostics);
3422
3457
  if (!isAudioSdp(sdp)) {
3423
3458
  throw new CodexRealtimeError(
3424
3459
  "invalid_response",
3425
3460
  "Codex realtime response was not an audio SDP answer",
3426
- response.status
3461
+ response.status,
3462
+ callDiagnostics
3427
3463
  );
3428
3464
  }
3429
3465
  return {
@@ -3437,12 +3473,27 @@ async function createCodexRealtimeCall(auth, input, fetchImpl = fetch, options =
3437
3473
  } catch (error) {
3438
3474
  if (error instanceof CodexRealtimeError) throw error;
3439
3475
  if (options.signal?.aborted) {
3440
- throw new CodexRealtimeError("cancelled", "Codex realtime request cancelled");
3476
+ throw new CodexRealtimeError(
3477
+ "cancelled",
3478
+ "Codex realtime request cancelled",
3479
+ null,
3480
+ callDiagnostics
3481
+ );
3441
3482
  }
3442
3483
  if (timedOut || controller.signal.aborted) {
3443
- throw new CodexRealtimeError("timeout", "Codex realtime request timed out");
3484
+ throw new CodexRealtimeError(
3485
+ "timeout",
3486
+ "Codex realtime request timed out",
3487
+ null,
3488
+ callDiagnostics
3489
+ );
3444
3490
  }
3445
- throw new CodexRealtimeError("network", "Codex realtime provider request failed");
3491
+ throw new CodexRealtimeError(
3492
+ "network",
3493
+ "Codex realtime provider request failed",
3494
+ null,
3495
+ callDiagnostics
3496
+ );
3446
3497
  } finally {
3447
3498
  if (timeout) clearTimeout(timeout);
3448
3499
  options.signal?.removeEventListener("abort", onAbort);
@@ -3501,32 +3552,92 @@ function validateRealtimeInput(input) {
3501
3552
  throw new CodexRealtimeError("invalid_request", "Codex realtime history is too large");
3502
3553
  }
3503
3554
  }
3504
- function providerHttpError(status) {
3555
+ async function readProviderErrorFields(response) {
3556
+ const declared = Number(response.headers.get("content-length"));
3557
+ if (!response.body || Number.isFinite(declared) && declared > MAX_REALTIME_ERROR_BODY_BYTES) {
3558
+ await response.body?.cancel().catch(() => void 0);
3559
+ return {};
3560
+ }
3561
+ let text = "";
3562
+ const reader = response.body.getReader();
3563
+ const decoder = new TextDecoder();
3564
+ let total = 0;
3565
+ try {
3566
+ while (true) {
3567
+ const next = await reader.read();
3568
+ if (next.done) break;
3569
+ total += next.value.byteLength;
3570
+ if (total > MAX_REALTIME_ERROR_BODY_BYTES) {
3571
+ await reader.cancel().catch(() => void 0);
3572
+ return {};
3573
+ }
3574
+ text += decoder.decode(next.value, { stream: true });
3575
+ }
3576
+ } catch {
3577
+ return {};
3578
+ } finally {
3579
+ reader.releaseLock();
3580
+ }
3581
+ let parsed;
3582
+ try {
3583
+ parsed = JSON.parse(text);
3584
+ } catch {
3585
+ return {};
3586
+ }
3587
+ if (!parsed || typeof parsed !== "object") return {};
3588
+ const record = parsed;
3589
+ const error = record.error && typeof record.error === "object" ? record.error : null;
3590
+ const code = providerErrorToken(error?.code) ?? providerErrorToken(record.detail);
3591
+ const type = providerErrorToken(error?.type);
3592
+ const param = providerErrorToken(error?.param);
3593
+ return {
3594
+ ...code ? { providerErrorCode: code } : {},
3595
+ ...type ? { providerErrorType: type } : {},
3596
+ ...param ? { providerErrorParam: param } : {}
3597
+ };
3598
+ }
3599
+ function providerErrorToken(value) {
3600
+ return typeof value === "string" && REALTIME_PROVIDER_ERROR_TOKEN.test(value) ? value : null;
3601
+ }
3602
+ function providerHttpError(status, diagnostics) {
3505
3603
  if (status === 401) {
3506
3604
  return new CodexRealtimeError(
3507
3605
  "authentication",
3508
3606
  "Codex subscription rejected authentication",
3509
- status
3607
+ status,
3608
+ diagnostics
3510
3609
  );
3511
3610
  }
3512
3611
  if (status === 403) {
3513
3612
  return new CodexRealtimeError(
3514
3613
  "entitlement",
3515
3614
  "Codex subscription lacks realtime entitlement",
3516
- status
3615
+ status,
3616
+ diagnostics
3517
3617
  );
3518
3618
  }
3519
3619
  if (status === 404) {
3520
3620
  return new CodexRealtimeError(
3521
3621
  "incompatible",
3522
3622
  "Codex subscription realtime is unavailable",
3523
- status
3623
+ status,
3624
+ diagnostics
3524
3625
  );
3525
3626
  }
3526
3627
  if (status === 429) {
3527
- return new CodexRealtimeError("rate_limited", "Codex realtime is rate limited", status);
3628
+ return new CodexRealtimeError(
3629
+ "rate_limited",
3630
+ "Codex realtime is rate limited",
3631
+ status,
3632
+ diagnostics
3633
+ );
3528
3634
  }
3529
- return new CodexRealtimeError("provider", "Codex realtime provider request failed", status);
3635
+ return new CodexRealtimeError(
3636
+ "provider",
3637
+ "Codex realtime provider request failed",
3638
+ status,
3639
+ diagnostics
3640
+ );
3530
3641
  }
3531
3642
  function validRealtimeLocation(location) {
3532
3643
  const path = location.split("?", 1)[0] ?? "";
@@ -3536,14 +3647,15 @@ function validRealtimeLocation(location) {
3536
3647
  function isAudioSdp(sdp) {
3537
3648
  return /^v=0(?:\r?\n)/.test(sdp) && /(?:^|\r?\n)m=audio\s/m.test(sdp);
3538
3649
  }
3539
- async function readBoundedSdp(response) {
3650
+ async function readBoundedSdp(response, diagnostics) {
3540
3651
  const declared = Number(response.headers.get("content-length"));
3541
3652
  if (Number.isFinite(declared) && declared > MAX_REALTIME_SDP_BYTES) {
3542
3653
  await response.body?.cancel().catch(() => void 0);
3543
3654
  throw new CodexRealtimeError(
3544
3655
  "invalid_response",
3545
3656
  "Codex realtime SDP answer is too large",
3546
- response.status
3657
+ response.status,
3658
+ diagnostics
3547
3659
  );
3548
3660
  }
3549
3661
  if (!response.body) return "";
@@ -3560,7 +3672,8 @@ async function readBoundedSdp(response) {
3560
3672
  throw new CodexRealtimeError(
3561
3673
  "invalid_response",
3562
3674
  "Codex realtime SDP answer is too large",
3563
- response.status
3675
+ response.status,
3676
+ diagnostics
3564
3677
  );
3565
3678
  }
3566
3679
  chunks.push(next.value);
@@ -3580,7 +3693,8 @@ async function readBoundedSdp(response) {
3580
3693
  throw new CodexRealtimeError(
3581
3694
  "invalid_response",
3582
3695
  "Codex realtime SDP answer was not valid UTF-8",
3583
- response.status
3696
+ response.status,
3697
+ diagnostics
3584
3698
  );
3585
3699
  }
3586
3700
  }