From ce42c58ba23e5fb32d2c3c28397791bc9b666b00 Mon Sep 17 00:00:00 2001 From: Kyle Mistele Date: Tue, 1 Sep 2026 18:34:53 -0700 Subject: [PATCH] fix: make ResponseErrorEvent stream fields optional to handle non-conformant providers The Codex backend sends SSE error events without `code`, `param`, or `sequence_number` keys. The @effect/ai-openai schema required these fields, and the UnknownResponseStreamEvent catch-all rejected known types like "error", so the stream decoder crashed instead of surfacing the error. Also upgrades @effect/* from rc.109 to rc.112, which subsumes the prior patch (reasoning "max", XaiErrorBody, 402 handling, billing_insufficient_balance). Co-Authored-By: Claude Opus 4.6 (1M context) HumanLayer-Session: https://app.dev.codelayer.gg/sessions/01a05fb1-a6be-71e1-b09c-40c04f49aa7c --- bun.lock | 34 ++-- package.json | 14 +- .../@effect%2Fai-openai@4.0.0-rc.109.patch | 166 ------------------ .../@effect%2Fai-openai@4.0.0-rc.112.patch | 90 ++++++++++ 4 files changed, 114 insertions(+), 190 deletions(-) delete mode 100644 patches/@effect%2Fai-openai@4.0.0-rc.109.patch create mode 100644 patches/@effect%2Fai-openai@4.0.0-rc.112.patch diff --git a/bun.lock b/bun.lock index aa46b09..32c37e4 100644 --- a/bun.lock +++ b/bun.lock @@ -214,14 +214,14 @@ }, }, "patchedDependencies": { - "@effect/ai-openai@4.0.0-rc.109": "patches/@effect%2Fai-openai@4.0.0-rc.109.patch", + "@effect/ai-openai@4.0.0-rc.112": "patches/@effect%2Fai-openai@4.0.0-rc.112.patch", }, "catalog": { - "@effect/ai-anthropic": "4.0.0-rc.109", - "@effect/ai-openai": "4.0.0-rc.109", - "@effect/ai-openai-compat": "4.0.0-rc.109", - "@effect/platform-node": "4.0.0-rc.109", - "@effect/vitest": "4.0.0-rc.109", + "@effect/ai-anthropic": "4.0.0-rc.112", + "@effect/ai-openai": "4.0.0-rc.112", + "@effect/ai-openai-compat": "4.0.0-rc.112", + "@effect/platform-node": "4.0.0-rc.112", + "@effect/vitest": "4.0.0-rc.112", "@kitlangton/terminal-control": "0.3.1", "@opentui/core": "0.4.3", "@opentui/keymap": "0.4.3", @@ -231,7 +231,7 @@ "@types/node": "26.1.0", "@types/turndown": "5.0.6", "@vitest/coverage-v8": "4.1.9", - "effect": "4.0.0-rc.109", + "effect": "4.0.0-rc.112", "solid-js": "1.9.12", "turndown": "7.2.4", "typescript": "7.0.2", @@ -299,15 +299,15 @@ "@bcoe/v8-coverage": ["@bcoe/v8-coverage@1.0.2", "", {}, "sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA=="], - "@effect/ai-anthropic": ["@effect/ai-anthropic@4.0.0-rc.109", "", { "peerDependencies": { "effect": "^4.0.0-rc.109" } }, "sha512-o/KINUP4iTAGQrE5+arEzXqHGesdT5WGxtn2Tjkcnv+0HbdSef7iLaAiZHxDeViq8e97ahbvB0d7i64wmtkR4g=="], + "@effect/ai-anthropic": ["@effect/ai-anthropic@4.0.0-rc.112", "", { "peerDependencies": { "effect": "^4.0.0-rc.112" } }, "sha512-2GQKD3IzfCJuS3DgeuBwUjEYk5iyOqgK5etQkYZ3Ho8IuL8BtGR9d8G5AIiRV0xkNy5DD4vGnDGSHxKWsW2TRg=="], - "@effect/ai-openai": ["@effect/ai-openai@4.0.0-rc.109", "", { "peerDependencies": { "effect": "^4.0.0-rc.109" } }, "sha512-S0lPmZROva8G6CDVAPYVAbztMnTQe+WO/TY9hXDdN4w/OdhcFN1YMVCX70gV8CrqHMZU7XPkghE9ZkA5Dw+4GA=="], + "@effect/ai-openai": ["@effect/ai-openai@4.0.0-rc.112", "", { "peerDependencies": { "effect": "^4.0.0-rc.112" } }, "sha512-j2X86xvgpAtNiusyESADHZn3PUzMVatE1zWXd0No2aybx/euKiVBVWZOtzq7ntJ5KvPHRBOFXTGPADdApQrwug=="], - "@effect/ai-openai-compat": ["@effect/ai-openai-compat@4.0.0-rc.109", "", { "peerDependencies": { "effect": "^4.0.0-rc.109" } }, "sha512-bA+1NOKJZvmNlLDFMWewTHNVW5fnEIJGyXtgQxT1LZs9l7MDCO9XIGj9Wuk9wRDuje0jkyP+kNyQLiUADuFwDQ=="], + "@effect/ai-openai-compat": ["@effect/ai-openai-compat@4.0.0-rc.112", "", { "peerDependencies": { "effect": "^4.0.0-rc.112" } }, "sha512-bfNYHgfjhzKhDwaw2na75JshGACrawSXWqqzTncBtBHpUIhZ+VHF2I5AdgCmfh6fnAuvhxcuJnzrixGOkG9YZw=="], - "@effect/platform-node": ["@effect/platform-node@4.0.0-rc.109", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-rc.109", "mime": "^4.1.0", "undici": "^8.7.0" }, "peerDependencies": { "effect": "^4.0.0-rc.109", "redis": ">=5.0.0 <7.0.0" } }, "sha512-LE/GTh6MCZ0uzbEFH9WmxQkC9snjWuFyh8vW04AAgbKKxSHXsepHSK9RcE/2oYKr6RhrOTD0C2wC0i+J9qoe2g=="], + "@effect/platform-node": ["@effect/platform-node@4.0.0-rc.112", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-rc.112", "mime": "^4.1.0", "undici": "^8.10.0" }, "peerDependencies": { "effect": "^4.0.0-rc.112", "redis": ">=5.0.0 <7.0.0" } }, "sha512-/BMAcdNGQQskLmI0Zoa95KfTZkr9HV9N4NSxaSrusG6GeW6Ulp9KvZ+Rlaiw8lnOt43CXjFLdfll5/k5rxL4hQ=="], - "@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-rc.109", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.21.0" }, "peerDependencies": { "effect": "^4.0.0-rc.109" } }, "sha512-jhZJnf81N7Z5+Z41Qr0cKT75WzGu6M1W05xrSdu/V8PK0kSFtU5hJMBxSGDWNlgWhBwK0WRZtnMHY8HLdONg1w=="], + "@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-rc.112", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.21.3" }, "peerDependencies": { "effect": "^4.0.0-rc.112" } }, "sha512-ttjz0xKamFN7vL8pNDYVwddJLjZvqKePc05djlz2VcdaKbLsnYbtMnL1rbOfHgEnIUSHGh7FkjaN4DM1Ov81sQ=="], "@effect/tsgo": ["@effect/tsgo@0.36.4", "", { "optionalDependencies": { "@effect/tsgo-darwin-arm64": "0.36.4", "@effect/tsgo-darwin-x64": "0.36.4", "@effect/tsgo-linux-arm": "0.36.4", "@effect/tsgo-linux-arm64": "0.36.4", "@effect/tsgo-linux-x64": "0.36.4", "@effect/tsgo-win32-arm64": "0.36.4", "@effect/tsgo-win32-x64": "0.36.4" }, "bin": { "effect-tsgo": "dist/effect-tsgo.cjs" } }, "sha512-fNmdUV6FgXnvIcG18AVS1SRXt7z9jsyBh5CKuJYmTsE+DgbLaWF0CevKHx7hQPcidDWRVmdJYfU66Jvc/ZEt6w=="], @@ -325,7 +325,7 @@ "@effect/tsgo-win32-x64": ["@effect/tsgo-win32-x64@0.36.4", "", { "os": "win32", "cpu": "x64" }, "sha512-q4j1q0ESYxxookjA0ECz/84DEH2MsP51K0aZb3uXKfxagHDASPoWDcVu4BJTcwrK5kdZzvw9QrCPjAXe9WZqng=="], - "@effect/vitest": ["@effect/vitest@4.0.0-rc.109", "", { "peerDependencies": { "effect": "^4.0.0-rc.109", "vitest": ">=4.1.0 <5.0.0" } }, "sha512-vu5ZkidJ/gM/+a0M07Jnq1PV4duFlYc+4Vj9TsJysK4Us7LL5bwV6uXiT7mi1/IM/3HgfAwc7Q9ROj8M65G4pA=="], + "@effect/vitest": ["@effect/vitest@4.0.0-rc.112", "", { "peerDependencies": { "effect": "^4.0.0-rc.112", "vitest": ">=4.1.0 <5.0.0" } }, "sha512-mEKh/FI64mt8JK1/v9mpOrJYdnp+UFZdRUBMEdZMiKz7klg6NPqVgg/oeAGH6wOOQc2iAPcfc2H9BbAv1KyzMQ=="], "@emnapi/core": ["@emnapi/core@1.11.1", "", { "dependencies": { "@emnapi/wasi-threads": "1.2.2", "tslib": "^2.4.0" } }, "sha512-RSvbQmHzdKzNsLYa/wHrbc3KN4sYLKAdPZxqiM2HATqv/SBk2/ENSHpvXGaLOMcsAyz0poEGqkmmKYG3OWiJEQ=="], @@ -669,7 +669,7 @@ "diff": ["diff@9.0.0", "", {}, "sha512-svtcdpS8CgJyqAjEQIXdb3OjhFVVYjzGAPO8WGCmRbrml64SPw/jJD4GoE98aR7r25A0XcgrK3F02yw9R/vhQw=="], - "effect": ["effect@4.0.0-rc.109", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.9.0", "msgpackr": "^2.0.4" } }, "sha512-6ubcOCtfdbmFO5+vgcT2HsTw5s+n3aMUj4eAIbVpUxP7+VYCwXxxcBHgiWgizOrGO1eGmuOBFek3mM0dFcwaWA=="], + "effect": ["effect@4.0.0-rc.112", "", { "dependencies": { "fast-check": "^4.9.0", "msgpackr": "^2.0.5" } }, "sha512-wXxwuh1Ywnv4cPRM3Wfa0vDwuOHnZ1TsTgHJkG9XgzND6inhBH9n1vBxhg3iIXOia/OrpmvVmd3lrD4vq6bF3A=="], "electron-to-chromium": ["electron-to-chromium@1.5.391", "", {}, "sha512-YmCu4856jkgKT1Nh6fwRdeVrM6Ydf/fBnq51tpmSfX+jOcUMTxh31yH6hjKScRenhB2oDSvA9oooxcpjogPeig=="], @@ -775,7 +775,7 @@ "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - "msgpackr": ["msgpackr@2.0.4", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.4" } }, "sha512-o1C5KRmuRt+apqMr1HuGSqWStZoRBUpEsCsl15uM9VdAF1qHLtvMOU2En747EnTyEl6c4pzPewRMFF31s1CNbA=="], + "msgpackr": ["msgpackr@2.1.0", "", { "optionalDependencies": { "msgpackr-extract": "^3.0.4" } }, "sha512-p/pBCVO63CsvvpkomUnNNag6+n38rULuDA6HHe70o2gtC8ODI52foF/4ko2qQcp6OiErJXTmrZeXmsGGHsIQNQ=="], "msgpackr-extract": ["msgpackr-extract@3.0.4", "", { "dependencies": { "node-gyp-build-optional-packages": "5.2.2" }, "optionalDependencies": { "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.4", "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.4", "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.4" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" } }, "sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw=="], @@ -879,7 +879,7 @@ "typescript": ["typescript@7.0.2", "", { "optionalDependencies": { "@typescript/typescript-aix-ppc64": "7.0.2", "@typescript/typescript-darwin-arm64": "7.0.2", "@typescript/typescript-darwin-x64": "7.0.2", "@typescript/typescript-freebsd-arm64": "7.0.2", "@typescript/typescript-freebsd-x64": "7.0.2", "@typescript/typescript-linux-arm": "7.0.2", "@typescript/typescript-linux-arm64": "7.0.2", "@typescript/typescript-linux-loong64": "7.0.2", "@typescript/typescript-linux-mips64el": "7.0.2", "@typescript/typescript-linux-ppc64": "7.0.2", "@typescript/typescript-linux-riscv64": "7.0.2", "@typescript/typescript-linux-s390x": "7.0.2", "@typescript/typescript-linux-x64": "7.0.2", "@typescript/typescript-netbsd-arm64": "7.0.2", "@typescript/typescript-netbsd-x64": "7.0.2", "@typescript/typescript-openbsd-arm64": "7.0.2", "@typescript/typescript-openbsd-x64": "7.0.2", "@typescript/typescript-sunos-x64": "7.0.2", "@typescript/typescript-win32-arm64": "7.0.2", "@typescript/typescript-win32-x64": "7.0.2" }, "bin": { "tsc": "bin/tsc" } }, "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA=="], - "undici": ["undici@8.7.0", "", {}, "sha512-N7iQtfyLhIMOFgQubvmLV26svHpO0bqKnAiWotTQCVKCmWrcGbBotPuW1x+xwYZ2VHdSTVUfPQQnlEt1/LouTQ=="], + "undici": ["undici@8.10.1", "", {}, "sha512-YQ3WlbqjYMmNpdvDH64jAgLjxuAR9+649calDWhbshYaeQGO2bR4nI94ORJmwI3J9YhoKQnpyGOK+0zlWS5N5Q=="], "undici-types": ["undici-types@8.3.0", "", {}, "sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ=="], @@ -893,7 +893,7 @@ "why-is-node-running": ["why-is-node-running@2.3.0", "", { "dependencies": { "siginfo": "^2.0.0", "stackback": "0.0.2" }, "bin": { "why-is-node-running": "cli.js" } }, "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w=="], - "ws": ["ws@8.21.1", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw=="], + "ws": ["ws@8.21.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw=="], "yallist": ["yallist@3.1.1", "", {}, "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="], diff --git a/package.json b/package.json index c68a9c8..11878d6 100644 --- a/package.json +++ b/package.json @@ -32,11 +32,11 @@ "@opentui/keymap": "0.4.3", "@opentui/solid": "0.4.3", "solid-js": "1.9.12", - "effect": "4.0.0-rc.109", - "@effect/ai-openai": "4.0.0-rc.109", - "@effect/ai-openai-compat": "4.0.0-rc.109", - "@effect/platform-node": "4.0.0-rc.109", - "@effect/vitest": "4.0.0-rc.109", + "effect": "4.0.0-rc.112", + "@effect/ai-openai": "4.0.0-rc.112", + "@effect/ai-openai-compat": "4.0.0-rc.112", + "@effect/platform-node": "4.0.0-rc.112", + "@effect/vitest": "4.0.0-rc.112", "@silvia-odwyer/photon-node": "0.3.4", "turndown": "7.2.4", "@types/turndown": "5.0.6", @@ -46,7 +46,7 @@ "typescript": "7.0.2", "@types/bun": "1.3.14", "@types/node": "26.1.0", - "@effect/ai-anthropic": "4.0.0-rc.109" + "@effect/ai-anthropic": "4.0.0-rc.112" } }, "devDependencies": { @@ -62,6 +62,6 @@ "vitest": "catalog:" }, "patchedDependencies": { - "@effect/ai-openai@4.0.0-rc.109": "patches/@effect%2Fai-openai@4.0.0-rc.109.patch" + "@effect/ai-openai@4.0.0-rc.112": "patches/@effect%2Fai-openai@4.0.0-rc.112.patch" } } diff --git a/patches/@effect%2Fai-openai@4.0.0-rc.109.patch b/patches/@effect%2Fai-openai@4.0.0-rc.109.patch deleted file mode 100644 index 6f0fa41..0000000 --- a/patches/@effect%2Fai-openai@4.0.0-rc.109.patch +++ /dev/null @@ -1,166 +0,0 @@ -diff --git a/dist/OpenAiLanguageModel.d.ts b/dist/OpenAiLanguageModel.d.ts ---- a/dist/OpenAiLanguageModel.d.ts -+++ b/dist/OpenAiLanguageModel.d.ts -@@ -41,7 +41,7 @@ declare const Config_base: Context.ServiceClass; - readonly model: Schema.optional; - readonly reasoning: Schema.optional>; -+ readonly effort: Schema.optional>; - readonly summary: Schema.optional>; - readonly generate_summary: Schema.optional>; - }>>; -diff --git a/dist/OpenAiSchema.js b/dist/OpenAiSchema.js ---- a/dist/OpenAiSchema.js -+++ b/dist/OpenAiSchema.js -@@ -417,7 +417,7 @@ export const CreateResponse = /*#__PURE__*/Schema.Struct({ - previous_response_id: /*#__PURE__*/Schema.optional(Schema.String), - model: /*#__PURE__*/Schema.optional(Schema.String), - reasoning: /*#__PURE__*/Schema.optional(/*#__PURE__*/Schema.Struct({ -- effort: /*#__PURE__*/Schema.optional(/*#__PURE__*/Schema.Literals(["none", "minimal", "low", "medium", "high", "xhigh"])), -+ effort: /*#__PURE__*/Schema.optional(/*#__PURE__*/Schema.Literals(["none", "minimal", "low", "medium", "high", "xhigh", "max"])), - summary: /*#__PURE__*/Schema.optional(/*#__PURE__*/Schema.Literals(["auto", "concise", "detailed"])), - generate_summary: /*#__PURE__*/Schema.optional(/*#__PURE__*/Schema.Literals(["auto", "concise", "detailed"])) - })), -diff --git a/dist/internal/errors.js b/dist/internal/errors.js ---- a/dist/internal/errors.js -+++ b/dist/internal/errors.js -@@ -19,6 +19,10 @@ export const OpenAiErrorBody = /*#__PURE__*/Schema.Struct({ - code: /*#__PURE__*/Schema.optional(/*#__PURE__*/Schema.NullOr(Schema.String)) - }) - }); -+const XaiErrorBody = /*#__PURE__*/Schema.Struct({ -+ error: Schema.String, -+ code: /*#__PURE__*/Schema.optional(Schema.String) -+}); - // ============================================================================= - // Error Mappers - // ============================================================================= -@@ -130,17 +134,20 @@ const mapStatusCodeError = /*#__PURE__*/Effect.fnUntraced(function* (error, meth - json = undefined; - } - const decoded = Schema.decodeUnknownOption(OpenAiErrorBody)(json); -+ const xaiDecoded = Schema.decodeUnknownOption(XaiErrorBody)(json); -+ const message = Option.isSome(decoded) ? decoded.value.error.message : Option.isSome(xaiDecoded) ? xaiDecoded.value.error : undefined; -+ const errorCode = Option.isSome(decoded) ? decoded.value.error.code ?? null : Option.isSome(xaiDecoded) ? xaiDecoded.value.code ?? null : null; - const reason = mapStatusCodeToReason({ - status, - headers, -- message: Option.isSome(decoded) ? decoded.value.error.message : undefined, -+ message, - http: buildHttpContext({ - request, - response, - body - }), - metadata: { -- errorCode: Option.isSome(decoded) ? decoded.value.error.code ?? null : null, -+ errorCode, - errorType: Option.isSome(decoded) ? decoded.value.error.type ?? null : null, - requestId: requestId ?? null - } -@@ -280,10 +287,17 @@ export const mapStatusCodeToReason = ({ - }, - http - }); -+ case 402: -+ return new AiError.QuotaExhaustedError({ -+ metadata: { -+ openai: metadata -+ }, -+ http -+ }); - case 429: - { - // Best-effort detection: OpenAI returns insufficient_quota for billing/quota issues -- if (metadata.errorCode === "insufficient_quota" || metadata.errorType === "insufficient_quota") { -+ if (metadata.errorCode === "insufficient_quota" || metadata.errorType === "insufficient_quota" || metadata.errorType === "billing_insufficient_balance") { - return new AiError.QuotaExhaustedError({ - metadata: { - openai: metadata -diff --git a/src/OpenAiSchema.ts b/src/OpenAiSchema.ts ---- a/src/OpenAiSchema.ts -+++ b/src/OpenAiSchema.ts -@@ -662,7 +662,6 @@ export const CreateResponse = Schema.Struct({ - previous_response_id: Schema.optional(Schema.String), - model: Schema.optional(Schema.String), - reasoning: Schema.optional(Schema.Struct({ -- effort: Schema.optional(Schema.Literals(["none", "minimal", "low", "medium", "high", "xhigh"])), -+ effort: Schema.optional(Schema.Literals(["none", "minimal", "low", "medium", "high", "xhigh", "max"])), -- - summary: Schema.optional(Schema.Literals(["auto", "concise", "detailed"])), - generate_summary: Schema.optional(Schema.Literals(["auto", "concise", "detailed"])) -diff --git a/src/internal/errors.ts b/src/internal/errors.ts ---- a/src/internal/errors.ts -+++ b/src/internal/errors.ts -@@ -28,6 +28,10 @@ export const OpenAiErrorBody = Schema.Struct({ - }) - }) -- -+const XaiErrorBody = Schema.Struct({ -+ error: Schema.String, -+ code: Schema.optional(Schema.String) -+}) -+ - // ============================================================================= - // Error Mappers - // ============================================================================= -@@ -147,14 +152,24 @@ const mapStatusCodeError = Effect.fnUntraced(function*( - json = undefined - } - const decoded = Schema.decodeUnknownOption(OpenAiErrorBody)(json) -+ const xaiDecoded = Schema.decodeUnknownOption(XaiErrorBody)(json) -+ const message = Option.isSome(decoded) -+ ? decoded.value.error.message -+ : Option.isSome(xaiDecoded) -+ ? xaiDecoded.value.error -+ : undefined -+ const errorCode = Option.isSome(decoded) -+ ? decoded.value.error.code ?? null -+ : Option.isSome(xaiDecoded) -+ ? xaiDecoded.value.code ?? null -+ : null -- - const reason = mapStatusCodeToReason({ - status, - headers, -- message: Option.isSome(decoded) ? decoded.value.error.message : undefined, -+ message, - http: buildHttpContext({ request, response, body }), - metadata: { -- errorCode: Option.isSome(decoded) ? decoded.value.error.code ?? null : null, -+ errorCode, - errorType: Option.isSome(decoded) ? decoded.value.error.type ?? null : null, - requestId: requestId ?? null - } -@@ -321,11 +337,17 @@ export const mapStatusCodeToReason = ({ status, headers, message, metadata, http - metadata: { openai: metadata }, - http - }) -+ case 402: -+ return new AiError.QuotaExhaustedError({ -+ metadata: { openai: metadata }, -+ http -+ }) - case 429: { - // Best-effort detection: OpenAI returns insufficient_quota for billing/quota issues - if ( - metadata.errorCode === "insufficient_quota" || -- metadata.errorType === "insufficient_quota" -+ metadata.errorType === "insufficient_quota" || -+ metadata.errorType === "billing_insufficient_balance" - ) { - return new AiError.QuotaExhaustedError({ - metadata: { openai: metadata }, diff --git a/patches/@effect%2Fai-openai@4.0.0-rc.112.patch b/patches/@effect%2Fai-openai@4.0.0-rc.112.patch new file mode 100644 index 0000000..999bdf6 --- /dev/null +++ b/patches/@effect%2Fai-openai@4.0.0-rc.112.patch @@ -0,0 +1,90 @@ +diff --git a/src/OpenAiSchema.ts b/src/OpenAiSchema.ts +--- a/src/OpenAiSchema.ts ++++ b/src/OpenAiSchema.ts +@@ -1045,10 +1045,10 @@ + + const ResponseErrorEvent = Schema.Struct({ + type: Schema.Literal("error"), +- code: Schema.NullOr(Schema.String), ++ code: Schema.optionalKey(Schema.NullOr(Schema.String)), + message: Schema.String, +- param: Schema.NullOr(Schema.String), +- sequence_number: Schema.Int, ++ param: Schema.optionalKey(Schema.NullOr(Schema.String)), ++ sequence_number: Schema.optionalKey(Schema.Int), + status: Schema.optionalKey(Schema.Int) + }) + +@@ -1056,11 +1056,11 @@ + const NestedResponseErrorEvent = Schema.Struct({ + type: Schema.Literal("error"), + error: Schema.Struct({ +- code: Schema.NullOr(Schema.String), ++ code: Schema.optionalKey(Schema.NullOr(Schema.String)), + message: Schema.String, +- param: Schema.NullOr(Schema.String) ++ param: Schema.optionalKey(Schema.NullOr(Schema.String)) + }), +- sequence_number: Schema.Int, ++ sequence_number: Schema.optionalKey(Schema.Int), + status: Schema.optionalKey(Schema.Int) + }).pipe( + Schema.decodeTo( +diff --git a/dist/OpenAiSchema.js b/dist/OpenAiSchema.js +--- a/dist/OpenAiSchema.js ++++ b/dist/OpenAiSchema.js +@@ -696,21 +696,21 @@ + }); + const ResponseErrorEvent = /*#__PURE__*/Schema.Struct({ + type: /*#__PURE__*/Schema.Literal("error"), +- code: /*#__PURE__*/Schema.NullOr(Schema.String), ++ code: /*#__PURE__*/Schema.optionalKey(/*#__PURE__*/Schema.NullOr(Schema.String)), + message: Schema.String, +- param: /*#__PURE__*/Schema.NullOr(Schema.String), +- sequence_number: Schema.Int, ++ param: /*#__PURE__*/Schema.optionalKey(/*#__PURE__*/Schema.NullOr(Schema.String)), ++ sequence_number: /*#__PURE__*/Schema.optionalKey(Schema.Int), + status: /*#__PURE__*/Schema.optionalKey(Schema.Int) + }); + // OpenAI can nest stream error details under `error`. + const NestedResponseErrorEvent = /*#__PURE__*/Schema.Struct({ + type: Schema.Literal("error"), + error: Schema.Struct({ +- code: Schema.NullOr(Schema.String), ++ code: Schema.optionalKey(Schema.NullOr(Schema.String)), + message: Schema.String, +- param: Schema.NullOr(Schema.String) ++ param: Schema.optionalKey(Schema.NullOr(Schema.String)) + }), +- sequence_number: Schema.Int, ++ sequence_number: Schema.optionalKey(Schema.Int), + status: Schema.optionalKey(Schema.Int) + }).pipe(/*#__PURE__*/Schema.decodeTo(ResponseErrorEvent, /*#__PURE__*/SchemaTransformation.transform({ + decode: ({ +diff --git a/dist/Generated.d.ts b/dist/Generated.d.ts +--- a/dist/Generated.d.ts ++++ b/dist/Generated.d.ts +@@ -3322,17 +3322,17 @@ + export declare const ResponseErrorCode: Schema.Literals; + export type ResponseErrorEvent = { + readonly "type": "error"; +- readonly "code": string | null; ++ readonly "code"?: string | null | undefined; + readonly "message": string; +- readonly "param": string | null; +- readonly "sequence_number": number; ++ readonly "param"?: string | null | undefined; ++ readonly "sequence_number"?: number | undefined; + }; + export declare const ResponseErrorEvent: Schema.Struct<{ + readonly type: Schema.Literal<"error">; +- readonly code: Schema.Union; ++ readonly code: Schema.optionalKey>; + readonly message: Schema.String; +- readonly param: Schema.Union; +- readonly sequence_number: Schema.Number; ++ readonly param: Schema.optionalKey>; ++ readonly sequence_number: Schema.optionalKey; + }>; + export type ResponseFileSearchCallCompletedEvent = { + readonly "type": "response.file_search_call.completed";